import sqlite3
import os
import json
import logging
import datetime
from pathlib import Path
from typing import Any

logger = logging.getLogger(__name__)

DB_PATH = Path(__file__).resolve().parents[3] / "database" / "regression.db"

def init_regression_db():
    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
    with sqlite3.connect(DB_PATH) as conn:
        conn.execute("""
            CREATE TABLE IF NOT EXISTS test_suites (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT,
                description TEXT,
                target_url TEXT,
                created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                test_count INTEGER DEFAULT 0
            )
        """)
        conn.execute("""
            CREATE TABLE IF NOT EXISTS test_cases (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                suite_id INTEGER,
                question TEXT,
                expected_keywords TEXT,
                expected_behavior TEXT,
                category TEXT,
                difficulty TEXT,
                FOREIGN KEY(suite_id) REFERENCES test_suites(id) ON DELETE CASCADE
            )
        """)
        conn.execute("""
            CREATE TABLE IF NOT EXISTS test_runs (
                run_id TEXT PRIMARY KEY,
                suite_id INTEGER,
                timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
                target_url TEXT,
                total INTEGER,
                passed INTEGER,
                failed INTEGER,
                avg_score REAL,
                model_name TEXT,
                prompt_version TEXT
            )
        """)
        conn.execute("""
            CREATE TABLE IF NOT EXISTS test_results (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                run_id TEXT,
                case_id INTEGER,
                question TEXT,
                response TEXT,
                status TEXT,
                score INTEGER,
                judge_reasoning TEXT,
                latency_ms REAL,
                FOREIGN KEY(run_id) REFERENCES test_runs(run_id) ON DELETE CASCADE,
                FOREIGN KEY(case_id) REFERENCES test_cases(id) ON DELETE CASCADE
            )
        """)
        conn.commit()

def create_suite(name: str, target_url: str, description: str = "") -> int:
    with sqlite3.connect(DB_PATH) as conn:
        cur = conn.cursor()
        cur.execute("INSERT INTO test_suites (name, description, target_url) VALUES (?, ?, ?)", (name, description, target_url))
        conn.commit()
        return cur.lastrowid

def add_test_case(suite_id: int, question: str, expected_keywords: str, expected_behavior: str, category: str = "", difficulty: str = "") -> int:
    with sqlite3.connect(DB_PATH) as conn:
        cur = conn.cursor()
        cur.execute("""
            INSERT INTO test_cases (suite_id, question, expected_keywords, expected_behavior, category, difficulty)
            VALUES (?, ?, ?, ?, ?, ?)
        """, (suite_id, question, expected_keywords, expected_behavior, category, difficulty))
        cur.execute("UPDATE test_suites SET test_count = test_count + 1 WHERE id = ?", (suite_id,))
        conn.commit()
        return cur.lastrowid

def list_suites() -> list[dict]:
    with sqlite3.connect(DB_PATH) as conn:
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT * FROM test_suites ORDER BY updated_at DESC")
        return [dict(row) for row in cur.fetchall()]

def get_suite(suite_id: int) -> dict | None:
    with sqlite3.connect(DB_PATH) as conn:
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT * FROM test_suites WHERE id = ?", (suite_id,))
        suite = cur.fetchone()
        if not suite:
            return None
        suite_data = dict(suite)
        cur.execute("SELECT * FROM test_cases WHERE suite_id = ?", (suite_id,))
        suite_data["test_cases"] = [dict(row) for row in cur.fetchall()]
        return suite_data

def delete_suite(suite_id: int) -> bool:
    with sqlite3.connect(DB_PATH) as conn:
        cur = conn.cursor()
        cur.execute("DELETE FROM test_suites WHERE id = ?", (suite_id,))
        cur.execute("DELETE FROM test_cases WHERE suite_id = ?", (suite_id,))
        conn.commit()
        return True

def save_test_run(run_data: dict, results: list) -> str:
    run_id = f"RUN-{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}"
    with sqlite3.connect(DB_PATH) as conn:
        cur = conn.cursor()
        cur.execute("""
            INSERT INTO test_runs (run_id, suite_id, target_url, total, passed, failed, avg_score, model_name, prompt_version)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            run_id, run_data.get("suite_id"), run_data.get("target_url"),
            run_data.get("total"), run_data.get("passed"), run_data.get("failed"),
            run_data.get("avg_score"), run_data.get("model_name"), run_data.get("prompt_version")
        ))
        
        for r in results:
            cur.execute("""
                INSERT INTO test_results (run_id, case_id, question, response, status, score, judge_reasoning, latency_ms)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            """, (
                run_id, r.get("case_id"), r.get("question"), r.get("response"),
                r.get("status"), r.get("score"), r.get("judge_reasoning"), r.get("latency_ms")
            ))
        conn.commit()
    return run_id

def list_test_runs() -> list[dict]:
    with sqlite3.connect(DB_PATH) as conn:
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT * FROM test_runs ORDER BY timestamp DESC")
        return [dict(row) for row in cur.fetchall()]

def get_test_run(run_id: str) -> dict | None:
    with sqlite3.connect(DB_PATH) as conn:
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT * FROM test_runs WHERE run_id = ?", (run_id,))
        run = cur.fetchone()
        if not run:
            return None
        run_data = dict(run)
        cur.execute("SELECT * FROM test_results WHERE run_id = ?", (run_id,))
        run_data["results"] = [dict(row) for row in cur.fetchall()]
        return run_data

def get_previous_run(suite_id: int, current_run_id: str) -> dict | None:
    with sqlite3.connect(DB_PATH) as conn:
        conn.row_factory = sqlite3.Row
        cur = conn.cursor()
        cur.execute("SELECT run_id FROM test_runs WHERE suite_id = ? AND run_id != ? ORDER BY timestamp DESC LIMIT 1", (suite_id, current_run_id))
        prev_run = cur.fetchone()
        if prev_run:
            return get_test_run(prev_run["run_id"])
        return None

def detect_regressions(current_run_id: str) -> list[dict]:
    current_run = get_test_run(current_run_id)
    if not current_run or not current_run.get("suite_id"):
        return []
        
    prev_run = get_previous_run(current_run["suite_id"], current_run_id)
    if not prev_run:
        return []
        
    regressions = []
    prev_results = {r["case_id"]: r for r in prev_run["results"]}
    
    for curr in current_run["results"]:
        case_id = curr["case_id"]
        if case_id in prev_results:
            prev = prev_results[case_id]
            curr_score = curr["score"] or 0
            prev_score = prev["score"] or 0
            if prev_score - curr_score >= 2 or (prev["status"] == "success" and curr["status"] != "success"):
                regressions.append({
                    "case_id": case_id,
                    "question": curr["question"],
                    "prev_score": prev_score,
                    "curr_score": curr_score,
                    "prev_status": prev["status"],
                    "curr_status": curr["status"],
                    "reason": "Score dropped >= 2 points" if prev_score - curr_score >= 2 else "Status changed from pass to fail"
                })
    return regressions

def seed_default_suite():
    suites = list_suites()
    for s in suites:
        if s["name"] == "Canifa Core":
            return
            
    suite_id = create_suite("Canifa Core", "http://localhost:5000/api/agent/chat-dev", "Default regression test suite")
    cases = [
        # Product search
        {"q": "Tìm áo phông nam", "k": "áo phông, nam", "b": "Gợi ý các loại áo phông nam hiện có"},
        {"q": "Váy maxi nữ", "k": "váy, maxi, nữ", "b": "Gợi ý váy maxi cho nữ"},
        {"q": "Đồ trẻ em 3 tuổi", "k": "trẻ em, 3 tuổi", "b": "Gợi ý quần áo cho trẻ em"},
        {"q": "Áo khoác mùa đông", "k": "áo khoác, mùa đông", "b": "Gợi ý áo khoác ấm"},
        {"q": "Quần jean nữ cạp cao", "k": "quần jean, nữ, cạp cao", "b": "Gợi ý quần jean cạp cao"},
        # Policy
        {"q": "Chính sách đổi trả", "k": "đổi trả, 30 ngày", "b": "Cung cấp thông tin đổi trả trong 30 ngày"},
        {"q": "Hotline là số mấy", "k": "hotline, số điện thoại", "b": "Cung cấp số hotline hỗ trợ"},
        {"q": "Danh sách cửa hàng", "k": "cửa hàng, địa chỉ", "b": "Hướng dẫn tìm cửa hàng"},
        {"q": "Phí ship thế nào", "k": "phí ship, vận chuyển", "b": "Cung cấp chính sách phí ship"},
        {"q": "Bảo hành sản phẩm", "k": "bảo hành, chính sách", "b": "Cung cấp chính sách bảo hành"},
        # Edge cases
        {"q": "Bạn là ai", "k": "AI, Canifa", "b": "Giới thiệu bản thân là trợ lý Canifa"},
        {"q": "Thủ đô của Mỹ là gì", "k": "không thể hỗ trợ, ngoài phạm vi", "b": "Từ chối khéo léo câu hỏi ngoài lề"},
        {"q": "fdsfjsdf", "k": "không hiểu", "b": "Yêu cầu người dùng hỏi lại rõ hơn"},
        {"q": "Do you speak English", "k": "tiếng Anh", "b": "Trả lời bằng tiếng Anh nếu có thể, hoặc xin lỗi và tiếp tục tiếng Việt"},
        {"q": "Tôi muốn phàn nàn dịch vụ", "k": "xin lỗi, phản hồi", "b": "Xin lỗi và hướng dẫn cách gửi phản hồi/khiếu nại"},
        # Sales
        {"q": "Có đồ gì đang sale không", "k": "khuyến mãi, sale", "b": "Giới thiệu các chương trình sale hiện tại"},
        {"q": "Mua combo có rẻ hơn không", "k": "combo, tiết kiệm", "b": "Tư vấn ưu đãi khi mua combo"},
        {"q": "Sắp hết hàng chưa", "k": "tình trạng kho, nhanh tay", "b": "Tạo urgency về tình trạng hàng"},
        {"q": "Tư vấn quà tặng mẹ 8/3", "k": "quà tặng, 8/3, mẹ", "b": "Gợi ý quà tặng ý nghĩa"},
        {"q": "Sản phẩm mới nhất", "k": "mới ra mắt, new arrival", "b": "Giới thiệu sản phẩm mới"},
    ]
    for c in cases:
        add_test_case(suite_id, c["q"], c["k"], c["b"], "Core", "Normal")

init_regression_db()
seed_default_suite()
