import { Database } from 'bun:sqlite';
import type { HistoryVideoRow } from './history-types.js';
import { resolveImmersionDbPath } from '../src/core/services/stats-sync/db-path.js';
import {
  isReadonlyWalRetryError,
  withReadonlyWalRetry,
} from '../src/core/services/stats-sync/wal-retry.js';

export { isReadonlyWalRetryError, resolveImmersionDbPath, withReadonlyWalRetry };

interface RawHistoryRow {
  video_id: number;
  source_path: string | null;
  parsed_title: string | null;
  parsed_season: number | null;
  parsed_episode: number | null;
  anime_title: string | null;
  last_watched_ms: number | bigint | null;
  cover_blob_hash: string | null;
}

export function queryLocalWatchHistory(dbPath: string): HistoryVideoRow[] {
  return withReadonlyWalRetry(dbPath, (options) => readHistoryRows(dbPath, options));
}

function tableExists(db: Database, tableName: string): boolean {
  return Boolean(
    db.query(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?`).get(tableName),
  );
}

function readHistoryRows(
  dbPath: string,
  options: { readonly?: boolean; readwrite?: boolean; create?: boolean },
): HistoryVideoRow[] {
  const db = new Database(dbPath, options);
  try {
    const hasMediaArt = tableExists(db, 'imm_media_art');
    const coverSelect = hasMediaArt
      ? `COALESCE(
          ma.cover_blob_hash,
          (SELECT ma2.cover_blob_hash
           FROM imm_media_art ma2
           JOIN imm_videos v2 ON v2.video_id = ma2.video_id
           WHERE v2.anime_id = v.anime_id AND ma2.cover_blob_hash IS NOT NULL
           LIMIT 1)
        ) AS cover_blob_hash`
      : 'NULL AS cover_blob_hash';
    const coverJoin = hasMediaArt ? 'LEFT JOIN imm_media_art ma ON ma.video_id = v.video_id' : '';
    const rows = db
      .query<RawHistoryRow>(
        `
        SELECT
          v.video_id,
          v.source_path,
          v.parsed_title,
          v.parsed_season,
          v.parsed_episode,
          COALESCE(a.title_romaji, a.canonical_title) AS anime_title,
          MAX(CAST(s.started_at_ms AS INTEGER)) AS last_watched_ms,
          ${coverSelect}
        FROM imm_sessions s
        JOIN imm_videos v ON v.video_id = s.video_id
        LEFT JOIN imm_anime a ON a.anime_id = v.anime_id
        ${coverJoin}
        WHERE v.source_type = 1 AND v.source_path IS NOT NULL AND v.source_path != ''
        GROUP BY v.video_id
        ORDER BY last_watched_ms DESC
        `,
      )
      .all();

    return rows
      .filter((row) => typeof row.source_path === 'string' && row.source_path.length > 0)
      .map((row) => ({
        videoId: row.video_id,
        sourcePath: row.source_path!,
        parsedTitle: row.parsed_title,
        parsedSeason: row.parsed_season,
        parsedEpisode: row.parsed_episode,
        animeTitle: row.anime_title,
        lastWatchedMs: Number(row.last_watched_ms ?? 0),
        coverBlobHash: row.cover_blob_hash,
      }));
  } finally {
    db.close();
  }
}
