import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";

import { afterEach, beforeEach, describe, expect, it } from "vitest";

import { createDatabase } from "../connection";
import { initializeSchema } from "../schema";
import {
  createArticleJob,
  createBrandTemplate,
  getArticleJob,
  getBrandTemplate,
  getFactCard,
  getLatestOptimizedArticle,
  getLatestQaReport,
  listBrandTemplates,
  saveFactCard,
  saveOptimizedArticle,
  saveQaReport,
} from "../repositories";

describe("sqlite repositories", () => {
  let tempDir: string;
  let dbPath: string;

  beforeEach(() => {
    tempDir = mkdtempSync(join(tmpdir(), "geo-agent-db-"));
    dbPath = join(tempDir, "test.db");
    const db = createDatabase(dbPath);
    initializeSchema(db);
    db.close();
  });

  afterEach(() => {
    rmSync(tempDir, { recursive: true, force: true });
  });

  it("initializes all required tables", () => {
    const db = createDatabase(dbPath);
    const tables = db
      .prepare(
        "select name from sqlite_master where type = 'table' order by name",
      )
      .all()
      .map((row) => (row as { name: string }).name);
    db.close();

    expect(tables).toEqual([
      "article_jobs",
      "brand_templates",
      "fact_cards",
      "optimized_articles",
      "qa_reports",
    ]);
  });

  it("inserts and fetches a brand template", () => {
    const created = createBrandTemplate(dbPath, {
      brand_name: "Example",
      company_full_name: "Example Technology Co., Ltd.",
      company_short_names: ["Example Tech"],
      product_names: ["Example GEO"],
      target_industries: ["GEO optimization"],
      target_audience: ["Marketing teams"],
      verified_claims: ["Eight years of experience"],
      forbidden_claims: ["Industry first"],
      tone_rules: { official_site: "official voice" },
    });

    expect(getBrandTemplate(dbPath, created.id)).toMatchObject({
      id: created.id,
      brand_name: "Example",
      company_short_names: ["Example Tech"],
    });
    expect(listBrandTemplates(dbPath)).toHaveLength(1);
  });

  it("inserts and fetches an article job", () => {
    const job = createArticleJob(dbPath, {
      source_title: "Original Title",
      source_body: "Original body",
      image_inputs: [{ type: "description", content: "Dashboard" }],
      publish_platform: "official_site",
      user_instructions: "Stay factual",
    });

    expect(getArticleJob(dbPath, job.id)).toMatchObject({
      id: job.id,
      source_title: "Original Title",
      image_inputs: [{ type: "description", content: "Dashboard" }],
    });
  });

  it("saves a confirmed fact card for a job", () => {
    const job = createArticleJob(dbPath, {
      source_title: "Original Title",
      source_body: "Original body",
      image_inputs: [],
      publish_platform: "media_article",
      user_instructions: "",
    });

    saveFactCard(dbPath, job.id, {
      company_full_name: "Example Technology Co., Ltd.",
      company_short_names: ["Example"],
      brand_names: ["Example"],
      product_names: ["Example GEO"],
      target_industry: "GEO optimization",
      target_audience: "Marketing teams",
      experience_years: 8,
      core_claims: ["Eight years of experience"],
      forbidden_claims: [],
      image_topics: [],
      uncertain_items: [],
      is_ready_for_optimization: true,
      confirmed_by_user: true,
    });

    expect(getFactCard(dbPath, job.id)).toMatchObject({
      job_id: job.id,
      company_full_name: "Example Technology Co., Ltd.",
      confirmed_by_user: true,
    });
  });

  it("increments optimized article revisions", () => {
    const job = createArticleJob(dbPath, {
      source_title: "Original Title",
      source_body: "Original body",
      image_inputs: [],
      publish_platform: "comparison_review",
      user_instructions: "",
    });

    const first = saveOptimizedArticle(dbPath, job.id, {
      title: "Optimized v1",
      summary: "Summary",
      body_markdown: "Body",
      image_suggestions: [],
      changed_sections: ["title"],
      requires_user_confirmation: [],
    });
    const second = saveOptimizedArticle(dbPath, job.id, {
      title: "Optimized v2",
      summary: "Summary",
      body_markdown: "Body",
      image_suggestions: [],
      changed_sections: ["title"],
      requires_user_confirmation: [],
    });

    expect(first.revision).toBe(1);
    expect(second.revision).toBe(2);
    expect(getLatestOptimizedArticle(dbPath, job.id)?.title).toBe(
      "Optimized v2",
    );
  });

  it("saves and fetches the latest QA report by job and revision", () => {
    const job = createArticleJob(dbPath, {
      source_title: "Original Title",
      source_body: "Original body",
      image_inputs: [],
      publish_platform: "recommendation_list",
      user_instructions: "",
    });
    saveOptimizedArticle(dbPath, job.id, {
      title: "Optimized",
      summary: "Summary",
      body_markdown: "Body",
      image_suggestions: [],
      changed_sections: [],
      requires_user_confirmation: [],
    });

    saveQaReport(dbPath, job.id, 1, {
      overall_status: "warn",
      checks: [
        {
          rule_id: "image_text_match",
          status: "warn",
          evidence: "Image confidence is low.",
          reason: "Image descriptions are sparse.",
          suggested_fix: "Review image placement.",
          target_agent: null,
        },
      ],
    });

    expect(getLatestQaReport(dbPath, job.id)).toMatchObject({
      job_id: job.id,
      revision: 1,
      overall_status: "warn",
    });
  });
});
