import { mkdir } from "node:fs/promises";
import { dirname } from "node:path";
import { drizzle } from "drizzle-orm/libsql";
import { createClient, type Client as LibSQLClient } from "@libsql/client";
import * as schema from "./skill-registry-schema.js";
import { resolveSkillRegistryDbPath } from "../home-paths.js";

export type SkillRegistryDb = ReturnType<typeof drizzle<typeof schema>>;

let _db: SkillRegistryDb | null = null;

const CREATE_SKILLS_TABLE = `
CREATE TABLE IF NOT EXISTS skills (
  id TEXT PRIMARY KEY,
  source_id TEXT NOT NULL,
  name TEXT NOT NULL,
  description TEXT,
  source_url TEXT,
  active_version_id TEXT,
  removed_at INTEGER,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL
)`;

const CREATE_SKILL_VERSIONS_TABLE = `
CREATE TABLE IF NOT EXISTS skill_versions (
  id TEXT PRIMARY KEY,
  skill_id TEXT NOT NULL,
  version TEXT NOT NULL,
  fetched_at INTEGER NOT NULL,
  cache_dir TEXT
)`;

const CREATE_SKILL_FILES_TABLE = `
CREATE TABLE IF NOT EXISTS skill_files (
  id TEXT PRIMARY KEY,
  version_id TEXT NOT NULL,
  path TEXT NOT NULL,
  kind TEXT NOT NULL,
  size_bytes INTEGER
)`;

const CREATE_COMMUNITY_RATINGS_TABLE = `
CREATE TABLE IF NOT EXISTS community_ratings (
  id TEXT PRIMARY KEY,
  skill_id TEXT NOT NULL,
  fetched_at INTEGER NOT NULL,
  average_rating REAL,
  rating_count INTEGER,
  source TEXT
)`;

const CREATE_SKILL_GROUPS_TABLE = `
CREATE TABLE IF NOT EXISTS skill_groups (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  description TEXT,
  is_builtin INTEGER NOT NULL DEFAULT 0,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL
)`;

const CREATE_SKILL_GROUP_MEMBERS_TABLE = `
CREATE TABLE IF NOT EXISTS skill_group_members (
  group_id TEXT NOT NULL,
  skill_id TEXT NOT NULL,
  added_at INTEGER NOT NULL,
  PRIMARY KEY (group_id, skill_id)
)`;

const CREATE_SKILL_GROUP_INHERITANCE_TABLE = `
CREATE TABLE IF NOT EXISTS skill_group_inheritance (
  child_group_id TEXT NOT NULL,
  parent_group_id TEXT NOT NULL,
  PRIMARY KEY (child_group_id, parent_group_id)
)`;

const CREATE_AGENT_SKILL_GROUPS_TABLE = `
CREATE TABLE IF NOT EXISTS agent_skill_groups (
  agent_id TEXT NOT NULL,
  group_id TEXT NOT NULL,
  assigned_at INTEGER NOT NULL,
  PRIMARY KEY (agent_id, group_id)
)`;

const CREATE_AGENT_SKILLS_TABLE = `
CREATE TABLE IF NOT EXISTS agent_skills (
  agent_id TEXT NOT NULL,
  skill_id TEXT NOT NULL,
  installed_at INTEGER NOT NULL,
  PRIMARY KEY (agent_id, skill_id)
)`;

const CREATE_PERSONAL_RATINGS_TABLE = `
CREATE TABLE IF NOT EXISTS personal_ratings (
  id TEXT PRIMARY KEY,
  skill_id TEXT NOT NULL,
  version_id TEXT,
  stars INTEGER NOT NULL,
  note TEXT,
  created_at INTEGER NOT NULL,
  updated_at INTEGER NOT NULL
)`;

const BUILTIN_GROUPS = [
  {
    id: "builtin/pm-essentials",
    name: "PM Essentials",
    description: "Core planning and project-management skills",
  },
  {
    id: "builtin/engineer-core",
    name: "Engineer Core",
    description: "Foundational engineering skills",
  },
  {
    id: "builtin/frontend",
    name: "Frontend",
    description: "UI and frontend development skills",
  },
  {
    id: "builtin/backend",
    name: "Backend",
    description: "API, database, and infrastructure skills",
  },
  {
    id: "builtin/creative",
    name: "Creative",
    description: "Writing, branding, and creative production",
  },
] as const;

async function seedBuiltinGroups(client: LibSQLClient): Promise<void> {
  const now = Date.now();
  for (const group of BUILTIN_GROUPS) {
    await client.execute({
      sql: `INSERT OR IGNORE INTO skill_groups (id, name, description, is_builtin, created_at, updated_at) VALUES (?, ?, ?, 1, ?, ?)`,
      args: [group.id, group.name, group.description, now, now],
    });
  }
}

export async function getSkillRegistryDb(): Promise<SkillRegistryDb> {
  if (_db !== null) return _db;

  const dbPath = resolveSkillRegistryDbPath();
  await mkdir(dirname(dbPath), { recursive: true });

  const client = createClient({ url: `file:${dbPath}` });
  _db = drizzle({ client, schema });

  await client.execute(CREATE_SKILLS_TABLE);
  await client.execute(CREATE_SKILL_VERSIONS_TABLE);
  await client.execute(CREATE_SKILL_FILES_TABLE);
  await client.execute(CREATE_COMMUNITY_RATINGS_TABLE);

  await client.execute(CREATE_SKILL_GROUPS_TABLE);
  await client.execute(CREATE_SKILL_GROUP_MEMBERS_TABLE);
  await client.execute(CREATE_SKILL_GROUP_INHERITANCE_TABLE);
  await client.execute(CREATE_AGENT_SKILL_GROUPS_TABLE);
  await client.execute(CREATE_AGENT_SKILLS_TABLE);
  await client.execute(CREATE_PERSONAL_RATINGS_TABLE);

  // Add usage-tracking columns to agent_skills if they don't exist yet (idempotent)
  const agentSkillsAlters = [
    `ALTER TABLE agent_skills ADD COLUMN task_count INTEGER NOT NULL DEFAULT 0`,
    `ALTER TABLE agent_skills ADD COLUMN avg_cost_usd REAL`,
    `ALTER TABLE agent_skills ADD COLUMN last_used_at INTEGER`,
    `ALTER TABLE agent_skills ADD COLUMN source TEXT NOT NULL DEFAULT 'managed'`,
  ];
  for (const sql of agentSkillsAlters) {
    try {
      await client.execute(sql);
    } catch {
      // Column already exists — ignore
    }
  }

  await seedBuiltinGroups(client);

  return _db;
}

/** Reset the singleton — used for test cleanup */
export function resetSkillRegistryDb(): void {
  _db = null;
}
