import os
import pathlib
import sys

import psycopg
import pytest

ROOT = pathlib.Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "db"))
from migrate import migrate  # noqa: E402

from aix import ai, config  # noqa: E402
from aix.db import Jsonb, connect  # noqa: E402
from aix.ids import new_anon_id, new_id  # noqa: E402
from aix.providers import set_provider  # noqa: E402
from aix.providers.fake import FakeProvider  # noqa: E402
from aix.storage import LocalStorage, set_storage  # noqa: E402

ADMIN_DSN = os.environ.get("AIX_TEST_ADMIN_DSN", "postgresql://aix:aix@localhost/postgres")
TEST_DB = "aix_pytest"
DSN = f"postgresql://aix:aix@localhost/{TEST_DB}"


@pytest.fixture()
def conn():
    with psycopg.connect(ADMIN_DSN, autocommit=True) as admin:
        admin.execute(f"DROP DATABASE IF EXISTS {TEST_DB} WITH (FORCE)")
        admin.execute(f"CREATE DATABASE {TEST_DB}")
    migrate(DSN)
    config.clear_cache()
    ai.reset_breakers()
    c = connect(DSN, autocommit=True)
    yield c
    c.close()


@pytest.fixture()
def storage(tmp_path):
    s = LocalStorage(str(tmp_path / "store"))
    set_storage(s)
    return s


@pytest.fixture()
def fake():
    f = FakeProvider()
    set_provider("fake", f)
    return f


WEIGHTS_LANG = {"correctness": 50, "completeness": 25, "spelling": 10, "grammar": 10, "handwriting": 5}


@pytest.fixture()
def world(conn):
    """Tenant + catalog + question set:
    Section A (compulsory): Q1 short answer, max 2 (single unit)
    Section B (answer any 1 of 2): Q2 creative ক(1) খ(2); Q3 creative ক(1) খ(2)
    total target = 2 + 3 = 5"""
    ids = {k: new_id() for k in ["tenant", "es", "cls", "cat", "subj", "exam", "qs", "secA", "secB",
                                 "q1", "q2", "q3", "u1", "u2a", "u2b", "u3a", "u3b", "batch"]}
    c = conn
    c.execute("INSERT INTO tenants (id, biddaloy_school_id, name, settings_json, credit_balance_milli) VALUES (%s,'SCH1','Test School',%s,1000000)",
              (ids["tenant"], Jsonb({"feedback_lang": "bn"})))
    c.execute("INSERT INTO education_systems VALUES (%s,'BISE','মাধ্যমিক','BISE General')", (ids["es"],))
    c.execute("INSERT INTO classes VALUES (%s,%s,'9','নবম','Class 9',9)", (ids["cls"], ids["es"]))
    c.execute("INSERT INTO subject_categories VALUES (%s,'language',%s)", (ids["cat"], Jsonb(WEIGHTS_LANG)))
    c.execute("""INSERT INTO subjects (id, class_id, code, name_bn, name_en, subject_category_id)
                 VALUES (%s,%s,'BAN1','বাংলা ১ম পত্র','Bangla 1st Paper',%s)""", (ids["subj"], ids["cls"], ids["cat"]))
    c.execute("INSERT INTO exams (id, tenant_id, name, academic_year) VALUES (%s,%s,'Half-Yearly','2026')",
              (ids["exam"], ids["tenant"]))
    c.execute("""INSERT INTO question_sets (id, tenant_id, exam_id, class_id, subject_id, syllabus_json, status,
                 total_questions, total_target_marks, step) VALUES (%s,%s,%s,%s,%s,%s,'locked',3,5,0.5)""",
              (ids["qs"], ids["tenant"], ids["exam"], ids["cls"], ids["subj"], Jsonb({"label": "Chapters 1-3"})))
    c.execute("INSERT INTO qs_sections VALUES (%s,%s,'A',1,NULL)", (ids["secA"], ids["qs"]))
    c.execute("INSERT INTO qs_sections VALUES (%s,%s,'B',2,1)", (ids["secB"], ids["qs"]))
    for qid, sec, label, typ, mx, sort in [("q1", "secA", "১", "short", 2, 1), ("q2", "secB", "২", "creative", 3, 2),
                                           ("q3", "secB", "৩", "creative", 3, 3)]:
        c.execute("""INSERT INTO questions (id, question_set_id, section_id, label, type, text, max_mark, sort)
                     VALUES (%s,%s,%s,%s,%s,%s,%s,%s)""",
                  (ids[qid], ids["qs"], ids[sec], label, typ, f"Question {label}", mx, sort))
    units = [("u1", "q1", None, 2), ("u2a", "q2", "ক", 1), ("u2b", "q2", "খ", 2), ("u3a", "q3", "ক", 1), ("u3b", "q3", "খ", 2)]
    for i, (uid, qid, label, mx) in enumerate(units):
        c.execute("""INSERT INTO scoring_units (id, question_id, label, sort, max_mark, model_answer_text, key_points_json)
                     VALUES (%s,%s,%s,%s,%s,%s,%s)""",
                  (ids[uid], ids[qid], label, i, mx, f"model answer {uid}",
                   Jsonb([{"id": "KP1", "text": "main point", "weight": 1, "mandatory": True}])))
    c.execute("INSERT INTO batches (id, tenant_id, question_set_id, class_id, status) VALUES (%s,%s,%s,%s,'processing')",
              (ids["batch"], ids["tenant"], ids["qs"], ids["cls"]))
    return ids


def add_script(conn, storage, world, pdf_bytes: bytes, roll: str = "23") -> str:
    sid = new_id()
    key = f"{world['tenant']}/batches/{world['batch']}/scripts/{sid}/original.pdf"
    storage.put(key, pdf_bytes)
    conn.execute("""INSERT INTO scripts (id, tenant_id, batch_id, roll_from_filename, anon_id, original_file_key,
                    original_checksum) VALUES (%s,%s,%s,%s,%s,%s,%s)""",
                 (sid, world["tenant"], world["batch"], roll, new_anon_id(), key, sid))
    return sid
