import type { SupabaseClient } from "@supabase/supabase-js";
import type {
  Comment,
  Note,
  NoteCategory,
  Page,
  PageStatus,
  ProjectWithPages,
  Signoff,
} from "@/lib/types";
import { NOTE_BUCKET } from "@/lib/constants";

const SIGNED_URL_TTL = 60 * 60; // 1 hour

interface NoteRow {
  id: string;
  page_id: string;
  content: string;
  image_path: string | null;
  category: string;
  resolved: boolean;
  author_email: string | null;
  created_at: string;
}

interface CommentRow {
  id: string;
  note_id: string;
  content: string;
  image_path: string | null;
  author_email: string | null;
  created_at: string;
}

/** Resolve private storage keys to short-lived signed URLs in one batch. */
export async function signImagePaths(
  supabase: SupabaseClient,
  paths: string[],
): Promise<Map<string, string>> {
  const signed = new Map<string, string>();
  if (paths.length === 0) return signed;

  const { data } = await supabase.storage
    .from(NOTE_BUCKET)
    .createSignedUrls(paths, SIGNED_URL_TTL);

  for (const item of data ?? []) {
    if (item.path && item.signedUrl) signed.set(item.path, item.signedUrl);
  }
  return signed;
}

export async function getProjectBySlug(
  supabase: SupabaseClient,
  slug: string,
): Promise<ProjectWithPages | null> {
  const { data: project } = await supabase
    .from("projects")
    .select("id, slug, name, staging_domain, live_domain")
    .eq("slug", slug)
    .maybeSingle();

  if (!project) return null;

  const { data: pageRows } = await supabase
    .from("pages")
    .select(
      "id, project_id, page_name, slug, status, signoff, tags",
    )
    .eq("project_id", project.id)
    .order("position", { ascending: true })
    .order("created_at", { ascending: true });

  const pages = pageRows ?? [];
  const pageIds = pages.map((p) => p.id);

  let noteRows: NoteRow[] = [];
  if (pageIds.length > 0) {
    const { data } = await supabase
      .from("notes")
      .select(
        "id, page_id, content, image_path, category, resolved, author_email, created_at",
      )
      .in("page_id", pageIds)
      .order("created_at", { ascending: true });
    noteRows = (data as NoteRow[] | null) ?? [];
  }

  const noteIds = noteRows.map((n) => n.id);
  let commentRows: CommentRow[] = [];
  if (noteIds.length > 0) {
    const { data } = await supabase
      .from("comments")
      .select("id, note_id, content, image_path, author_email, created_at")
      .in("note_id", noteIds)
      .order("created_at", { ascending: true });
    commentRows = (data as CommentRow[] | null) ?? [];
  }

  // Sign all image paths (notes + comments) in one batch.
  const signedUrls = await signImagePaths(supabase, [
    ...noteRows.flatMap((n) => (n.image_path ? [n.image_path] : [])),
    ...commentRows.flatMap((c) => (c.image_path ? [c.image_path] : [])),
  ]);

  const commentsByNote = new Map<string, Comment[]>();
  for (const c of commentRows) {
    const comment: Comment = {
      id: c.id,
      note_id: c.note_id,
      content: c.content,
      image_url: c.image_path ? signedUrls.get(c.image_path) ?? null : null,
      author_email: c.author_email,
      created_at: c.created_at,
    };
    const list = commentsByNote.get(c.note_id) ?? [];
    list.push(comment);
    commentsByNote.set(c.note_id, list);
  }

  const notesByPage = new Map<string, Note[]>();
  for (const n of noteRows) {
    const note: Note = {
      id: n.id,
      page_id: n.page_id,
      content: n.content,
      image_url: n.image_path ? signedUrls.get(n.image_path) ?? null : null,
      category: n.category as NoteCategory,
      resolved: n.resolved,
      author_email: n.author_email,
      created_at: n.created_at,
      comments: commentsByNote.get(n.id) ?? [],
    };
    const list = notesByPage.get(n.page_id) ?? [];
    list.push(note);
    notesByPage.set(n.page_id, list);
  }

  const fullPages: Page[] = pages.map((p) => ({
    id: p.id,
    project_id: p.project_id,
    page_name: p.page_name,
    slug: p.slug ?? "",
    status: p.status as PageStatus,
    signoff: p.signoff as Signoff,
    tags: (p.tags as string[] | null) ?? [],
    notes: notesByPage.get(p.id) ?? [],
  }));

  return {
    id: project.id,
    slug: project.slug,
    name: project.name,
    staging_domain: project.staging_domain ?? null,
    live_domain: project.live_domain ?? null,
    pages: fullPages,
  };
}

export interface ProjectSummary {
  id: string;
  slug: string;
  name: string;
  pageCount: number;
}

export async function getProjectSummaries(
  supabase: SupabaseClient,
): Promise<ProjectSummary[]> {
  const { data } = await supabase
    .from("projects")
    .select("id, slug, name, pages(count)")
    .order("name", { ascending: true });

  return (data ?? []).map((p) => ({
    id: p.id,
    slug: p.slug,
    name: p.name,
    // Supabase returns an aggregate relation as [{ count }].
    pageCount:
      Array.isArray(p.pages) && p.pages.length > 0
        ? (p.pages[0] as { count: number }).count
        : 0,
  }));
}
