import json

from .base import BaseRepo


class IssueRepo(BaseRepo):
    def __init__(self, conn, project_dir: str = "", engine=None):
        super().__init__(conn, project_dir)
        self.engine = engine

    def _next_number(self) -> int:
        r1 = self.conn.execute(
            "SELECT MAX(issue_number) as m FROM issues WHERE project_dir=?",
            (self.project_dir,)
        ).fetchone()
        r2 = self.conn.execute(
            "SELECT MAX(issue_number) as m FROM issues_archive WHERE project_dir=?",
            (self.project_dir,)
        ).fetchone()
        m1 = r1["m"] or 0
        m2 = r2["m"] or 0
        return max(m1, m2) + 1

    def create(self, date: str, title: str, description: str = "", feature_id: str = "",
               parent_id: int = 0, memory_id: str = "") -> dict:
        issue_number = self._next_number()
        issue_id = f"issue-{issue_number}"
        now = self._now()
        self.conn.execute(
            "INSERT INTO issues (id, project_dir, issue_number, date, title, description, status, "
            "feature_id, parent_id, memory_id, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",
            (issue_id, self.project_dir, issue_number, date, title, description, "pending",
             feature_id, parent_id, memory_id, now, now)
        )
        self._commit()
        return self.get(issue_number)

    def get(self, issue_number: int) -> dict:
        row = self.conn.execute(
            "SELECT * FROM issues WHERE project_dir=? AND issue_number=?",
            (self.project_dir, issue_number)
        ).fetchone()
        return dict(row) if row else {}

    def update(self, issue_number: int, **fields) -> dict:
        if not fields:
            return self.get(issue_number)
        fields["updated_at"] = self._now()
        set_clause = ", ".join(f"{k}=?" for k in fields)
        self.conn.execute(
            f"UPDATE issues SET {set_clause} WHERE project_dir=? AND issue_number=?",
            [*fields.values(), self.project_dir, issue_number]
        )
        self._commit()
        return self.get(issue_number)

    def delete(self, issue_number: int) -> bool:
        cursor = self.conn.execute(
            "DELETE FROM issues WHERE project_dir=? AND issue_number=?",
            (self.project_dir, issue_number)
        )
        self._commit()
        return cursor.rowcount > 0

    def list_active(self, status: str | None = None, brief: bool = False, limit: int = 50) -> tuple[list[dict], int]:
        sql = "SELECT * FROM issues WHERE project_dir=?"
        params = [self.project_dir]
        if status:
            sql += " AND status=?"
            params.append(status)
        sql += " ORDER BY issue_number DESC LIMIT ?"
        params.append(limit)
        rows = [dict(r) for r in self.conn.execute(sql, params).fetchall()]
        if brief:
            rows = [{k: v for k, v in r.items() if k in ("id", "issue_number", "date", "title", "status", "feature_id")} for r in rows]
        total = self.conn.execute("SELECT COUNT(*) as c FROM issues WHERE project_dir=?", (self.project_dir,)).fetchone()["c"]
        return rows, total

    def list_by_date(self, date: str, status: str | None = None, brief: bool = False, limit: int = 50) -> tuple[list[dict], int]:
        sql = "SELECT * FROM issues WHERE project_dir=? AND date=?"
        params = [self.project_dir, date]
        if status:
            sql += " AND status=?"
            params.append(status)
        sql += " ORDER BY issue_number DESC LIMIT ?"
        params.append(limit)
        rows = [dict(r) for r in self.conn.execute(sql, params).fetchall()]
        if brief:
            rows = [{k: v for k, v in r.items() if k in ("id", "issue_number", "date", "title", "status", "feature_id")} for r in rows]
        total = self.conn.execute(
            "SELECT COUNT(*) as c FROM issues WHERE project_dir=? AND date=?",
            (self.project_dir, date)
        ).fetchone()["c"]
        return rows, total

    def archive(self, issue_number: int) -> dict:
        issue = self.get(issue_number)
        if not issue:
            return {}
        now = self._now()
        emb_blob = b""
        if self.engine:
            text = f"{issue['title']}\n{issue.get('description', '')}"
            emb = self.engine.encode(text)
            emb_blob = json.dumps(emb).encode("utf-8")
        
        self.conn.execute(
            "INSERT INTO issues_archive (id, project_dir, issue_number, date, title, description, investigation, "
            "root_cause, solution, test_result, files_changed, notes, feature_id, parent_id, status, memory_id, "
            "original_issue_id, created_at, updated_at, archived_at) "
            "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
            (issue["id"], self.project_dir, issue_number, issue["date"], issue["title"],
             issue.get("description", ""), issue.get("investigation", ""), issue.get("root_cause", ""),
             issue.get("solution", ""), issue.get("test_result", ""), issue.get("files_changed", ""),
             issue.get("notes", ""), issue.get("feature_id", ""), issue.get("parent_id", 0),
             issue.get("status", ""), issue.get("memory_id", ""), issue_number,
             issue["created_at"], issue["updated_at"], now)
        )
        
        if emb_blob:
            rowid = self.conn.execute(
                "SELECT rowid FROM issues_archive WHERE id=?", (issue["id"],)
            ).fetchone()["rowid"]
            self.conn.execute("INSERT INTO vec_issues_archive (rowid, embedding) VALUES (?,?)", (rowid, emb_blob))
        
        self.conn.execute(
            "DELETE FROM issues WHERE project_dir=? AND issue_number=?",
            (self.project_dir, issue_number)
        )
        self._commit()
        return issue

    def list_archived(self, brief: bool = False, limit: int = 50) -> tuple[list[dict], int]:
        sql = "SELECT * FROM issues_archive WHERE project_dir=? ORDER BY archived_at DESC LIMIT ?"
        rows = [dict(r) for r in self.conn.execute(sql, (self.project_dir, limit)).fetchall()]
        if brief:
            rows = [{k: v for k, v in r.items() if k in ("id", "issue_number", "date", "title", "status", "feature_id", "archived_at")} for r in rows]
        total = self.conn.execute("SELECT COUNT(*) as c FROM issues_archive WHERE project_dir=?", (self.project_dir,)).fetchone()["c"]
        return rows, total

    def search_archived(self, embedding: list[float], top_k: int = 5) -> list[dict]:
        emb_blob = json.dumps(embedding).encode("utf-8")
        sql = """
            SELECT a.*, vec_distance_cosine(v.embedding, ?) as distance
            FROM issues_archive a
            JOIN vec_issues_archive v ON a.rowid = v.rowid
            WHERE a.project_dir=?
            ORDER BY distance LIMIT ?
        """
        return [dict(r) for r in self.conn.execute(sql, (emb_blob, self.project_dir, top_k)).fetchall()]

    def get_archived(self, issue_id: str) -> dict:
        row = self.conn.execute(
            "SELECT * FROM issues_archive WHERE project_dir=? AND id=?",
            (self.project_dir, issue_id)
        ).fetchone()
        return dict(row) if row else {}

    def delete_archived(self, issue_id: str) -> bool:
        cursor = self.conn.execute(
            "DELETE FROM issues_archive WHERE project_dir=? AND id=?",
            (self.project_dir, issue_id)
        )
        self._commit()
        return cursor.rowcount > 0

    def get_by_feature(self, feature_id: str) -> list[dict]:
        return [dict(r) for r in self.conn.execute(
            "SELECT * FROM issues WHERE project_dir=? AND feature_id=? ORDER BY issue_number DESC",
            (self.project_dir, feature_id)
        ).fetchall()]

    def count_by_feature(self, feature_id: str) -> int:
        row = self.conn.execute(
            "SELECT COUNT(*) as c FROM issues WHERE project_dir=? AND feature_id=?",
            (self.project_dir, feature_id)
        ).fetchone()
        return row["c"]
