export const prerender = false;

import type { APIRoute } from 'astro';
import { isAuthenticated, ADMIN_COOKIE } from '@admin/lib/admin-auth';
import {
  remapTitleMetadataFields,
  remapTitleMetadataPayload,
  TITLE_METADATA_EDITABLE_COLUMNS,
} from '@/lib/catalog-metadata';
import { buildDefaultMovieSlugs } from '@/lib/movie-slug';
import {
  listTitleSlugs,
  normalizeTitleSlugInput,
  syncGeneratedTitleSlugs,
} from '@/lib/title-slugs';

interface Env { DB: D1Database }

function auth(locals: App.Locals, cookies: any) {
  const runtime = locals.runtime as { env: Env } | undefined;
  return { db: runtime?.env?.DB, cookie: cookies.get(ADMIN_COOKIE)?.value };
}

type AdminTitleSlugInput = {
  id?: number;
  slug: string;
  label: string | null;
  source_key: string | null;
  is_canonical: boolean;
};

function normalizeAdminTitleSlugPayload(
  value: unknown,
  titleId: string,
  titleEn: string | null | undefined,
  releaseDate: string | null | undefined,
): AdminTitleSlugInput[] {
  if (!Array.isArray(value)) return [];

  const defaultSlugMap = new Map(
    buildDefaultMovieSlugs(titleEn, titleId, releaseDate).map((slug) => [slug.sourceKey, slug]),
  );
  const deduped = new Map<string, AdminTitleSlugInput>();

  for (const rawEntry of value) {
    if (!rawEntry || typeof rawEntry !== 'object' || Array.isArray(rawEntry)) continue;
    const entry = rawEntry as Record<string, unknown>;
    const slug = normalizeTitleSlugInput(typeof entry.slug === 'string' ? entry.slug : null);
    if (!slug) continue;

    const rawSourceKey = typeof entry.source_key === 'string' ? entry.source_key.trim() : '';
    const defaultSlug = rawSourceKey ? defaultSlugMap.get(rawSourceKey) : undefined;
    const submittedLabel = typeof entry.label === 'string' ? entry.label.trim() : '';
    const label = submittedLabel || defaultSlug?.label || null;

    deduped.set(slug, {
      id: typeof entry.id === 'number' && Number.isInteger(entry.id) ? entry.id : undefined,
      slug,
      label,
      source_key: defaultSlug && slug === defaultSlug.slug && label === defaultSlug.label ? rawSourceKey : null,
      is_canonical: entry.is_canonical === true || entry.is_canonical === 1 || entry.is_canonical === '1',
    });
  }

  const normalized = [...deduped.values()];
  if (normalized.length === 0) return normalized;

  let lastCanonicalIndex = -1;
  for (let index = 0; index < normalized.length; index += 1) {
    if (normalized[index].is_canonical) {
      lastCanonicalIndex = index;
    }
  }
  const canonicalIndex = lastCanonicalIndex >= 0 ? lastCanonicalIndex : 0;
  return normalized.map((entry, index) => ({
    ...entry,
    is_canonical: index === canonicalIndex,
  }));
}

async function persistTitleSlugs(
  db: D1Database,
  titleId: string,
  titleEn: string | null | undefined,
  releaseDate: string | null | undefined,
  requestedSlugs: AdminTitleSlugInput[],
) {
  const existingRows = await listTitleSlugs(db, titleId);
  const existingById = new Map(existingRows.map((row) => [row.id, row] as const));
  const requestedIds = new Set<number>();

  for (const slugEntry of requestedSlugs) {
    if (typeof slugEntry.id === 'number') {
      requestedIds.add(slugEntry.id);
    }
  }

  for (const row of existingRows) {
    if (!requestedIds.has(row.id)) {
      await db.prepare('DELETE FROM title_slugs WHERE id = ? AND title_id = ?').bind(row.id, titleId).run();
    }
  }

  for (const slugEntry of requestedSlugs) {
    if (typeof slugEntry.id === 'number' && existingById.has(slugEntry.id)) {
      const current = existingById.get(slugEntry.id)!;
      const label = slugEntry.label ?? null;
      const sourceKey = slugEntry.source_key ?? null;
      const shouldUpdate =
        current.slug !== slugEntry.slug ||
        Number(current.is_canonical) !== Number(slugEntry.is_canonical) ||
        (current.label ?? null) !== label ||
        (current.source_key ?? null) !== sourceKey;

      if (shouldUpdate) {
        await db.prepare(
          `UPDATE title_slugs
              SET slug = ?,
                  is_canonical = ?,
                  label = ?,
                  source_key = ?,
                  updated_at = datetime('now')
            WHERE id = ? AND title_id = ?`,
        ).bind(
          slugEntry.slug,
          slugEntry.is_canonical ? 1 : 0,
          label,
          sourceKey,
          slugEntry.id,
          titleId,
        ).run();
      }
      continue;
    }

    await db.prepare(
      `INSERT INTO title_slugs (title_id, slug, is_canonical, label, source_key, created_at, updated_at)
       VALUES (?, ?, ?, ?, ?, datetime('now'), datetime('now'))`,
    ).bind(
      titleId,
      slugEntry.slug,
      slugEntry.is_canonical ? 1 : 0,
      slugEntry.label ?? null,
      slugEntry.source_key ?? null,
    ).run();
  }

  await syncGeneratedTitleSlugs(db, titleId, titleEn, titleId, releaseDate);
}

export const GET: APIRoute = async ({ locals, cookies, params }) => {
  const { db, cookie } = auth(locals, cookies);
  if (!db || !await isAuthenticated(cookie, db)) {
    return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
  }
  const row = await db.prepare('SELECT * FROM titles WHERE id = ?').bind(params.id).first();
  if (!row) return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });
  const slugs = await listTitleSlugs(db, params.id!);
  return new Response(JSON.stringify({ ...remapTitleMetadataFields(row as Record<string, unknown>), slugs }), {
    headers: { 'Content-Type': 'application/json' },
  });
};

export const PUT: APIRoute = async ({ request, locals, cookies, params }) => {
  const { db, cookie } = auth(locals, cookies);
  if (!db || !await isAuthenticated(cookie, db)) {
    return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
  }

  let body: Record<string, unknown>;
  try { body = remapTitleMetadataPayload(await request.json() as Record<string, unknown>); } catch { return new Response(JSON.stringify({ error: 'Invalid JSON' }), { status: 400 }); }

  const current = await db.prepare('SELECT * FROM titles WHERE id = ?').bind(params.id).first<Record<string, unknown>>();
  if (!current) return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });

  const EDITABLE = [
    'title_en', 'title_ar', 'title_ku', 'title_original',
    'language', 'subtitles', 'genre_raw', 'genre_ids', 'duration_min',
    'synopsis_en', 'synopsis_ar',
    'poster_url', 'backdrop_url', 'trailer_url',
    'imdb_id', 'elcinema_id', 'release_date',
    'director', 'cast_list', 'tags',
    'status', 'is_independent', 'is_featured', 'is_enabled',
    ...TITLE_METADATA_EDITABLE_COLUMNS,
  ] as const;

  const sets: string[] = [];
  const vals: unknown[] = [];
  for (const col of EDITABLE) {
    if (col in body) {
      sets.push(`${col} = ?`);
      vals.push(body[col] === '' ? null : body[col]);
    }
  }

  const nextTitleEn = typeof body.title_en === 'string' && body.title_en.trim()
    ? body.title_en
    : typeof current.title_en === 'string'
      ? current.title_en
      : null;
  const nextReleaseDate = typeof body.release_date === 'string' && body.release_date.trim()
    ? body.release_date
    : typeof current.release_date === 'string'
      ? current.release_date
      : null;
  const slugPayload = normalizeAdminTitleSlugPayload(body.slugs, params.id!, nextTitleEn, nextReleaseDate);

  if (!sets.length && !('slugs' in body)) {
    return new Response(JSON.stringify({ error: 'Nothing to update' }), { status: 400 });
  }

  if (sets.length) {
    sets.push(`updated_at = ?`);
    vals.push(new Date().toISOString());
    vals.push(params.id);

    await db.prepare(`UPDATE titles SET ${sets.join(', ')} WHERE id = ?`).bind(...vals).run();
  }

  if ('slugs' in body) {
    await persistTitleSlugs(db, params.id!, nextTitleEn, nextReleaseDate, slugPayload);
  } else {
    await syncGeneratedTitleSlugs(db, params.id!, nextTitleEn, params.id!, nextReleaseDate);
  }

  const updated = await db.prepare('SELECT * FROM titles WHERE id = ?').bind(params.id).first<Record<string, unknown>>();
  const slugs = await listTitleSlugs(db, params.id!);
  return new Response(JSON.stringify({ ...remapTitleMetadataFields(updated as Record<string, unknown>), slugs }), {
    headers: { 'Content-Type': 'application/json' },
  });
};
