import { eq, inArray, asc, sql } from "drizzle-orm";
import { db } from "@/db";
import { clients, projects, phases, tasks, deliverables, payments, documents, notes, comments, project_offers, offer_micros, offer_micro_services, offer_services } from "@/db/schema";

/**
 * ClientView: Legacy shape used by ClientDashboard component.
 * Kept for backward compatibility — new code uses ProjectView.
 * Deliberately excludes: quote_items, service_catalog, service prices, payment amounts.
 */
export interface ClientView {
  client: {
    id: string;
    name: string;
    brand_name: string;
    brief: string;
    accepted_total: string;
  };
  phases: Array<{
    id: string;
    title: string;
    status: "upcoming" | "active" | "done";
    sort_order: number;
    tasks: Array<{
      id: string;
      title: string;
      description: string | null;
      status: "todo" | "in_progress" | "done";
      sort_order: number;
      deliverables: Array<{
        id: string;
        title: string;
        url: string | null;
        status: "pending" | "submitted" | "approved";
        approved_at: string | null;
      }>;
    }>;
    progress_pct: number;
  }>;
  payments: Array<{
    id: string;
    label: string;
    status: "da_saldare" | "inviata" | "saldato";
  }>;
  documents: Array<{
    id: string;
    label: string;
    url: string;
  }>;
  notes: Array<{
    id: string;
    body: string;
    created_at: string;
  }>;
  global_progress_pct: number;
  activeOffers?: Array<{
    id: string;
    public_name: string;
    cumulative_price: string;
    accepted_total: string | null;
  }>;
}

export interface ProjectView {
  project: {
    id: string;
    name: string;
    client_id: string;
    accepted_total: string;
  };
  phases: Array<{
    id: string;
    title: string;
    status: string;
    sort_order: number;
    tasks: Array<{
      id: string;
      title: string;
      description: string | null;
      status: string;
      sort_order: number;
      deliverables: Array<{
        id: string;
        title: string;
        url: string | null;
        status: string;
        approved_at: Date | null;
        task_id: string;
      }>;
    }>;
    progress_pct: number;
  }>;
  payments: Array<{
    id: string;
    label: string;
    // amount intentionally excluded — client API never exposes payment amounts (CLAUDE.md + DASH-07)
    status: string;
  }>;
  documents: Array<{
    id: string;
    label: string;
    url: string;
    created_at: Date;
  }>;
  notes: Array<{
    id: string;
    body: string;
    created_at: Date;
  }>;
  comments: Array<{
    id: string;
    entity_type: string;
    entity_id: string;
    author: string;
    body: string;
    created_at: Date;
  }>;
  global_progress_pct: number;
  activeOffers?: Array<{
    id: string;
    public_name: string;        // offer_micros.public_name — NEVER internal_name
    cumulative_price: string;   // sum of assigned offer_services.price
    accepted_total: string | null;
  }>;
}

export interface ClientProjectSummary {
  client: {
    id: string;
    name: string;
    brand_name: string;
    token: string;
    slug: string | null;
  };
  projects: Array<{
    id: string;
    name: string;
    archived: boolean;
  }>;
}

/**
 * Resolves a token-or-slug to a client and returns the client's active projects.
 * Lookup order: slug first, then token — mirrors middleware order (D-06).
 */
export async function getClientWithProjectsByToken(
  tokenOrSlug: string
): Promise<ClientProjectSummary | null> {
  try {
  // Try slug first
  let clientRows = await db
    .select({
      id: clients.id,
      name: clients.name,
      brand_name: clients.brand_name,
      token: clients.token,
      slug: clients.slug,
    })
    .from(clients)
    .where(eq(clients.slug, tokenOrSlug))
    .limit(1);

  // Fall back to token
  if (clientRows.length === 0) {
    clientRows = await db
      .select({
        id: clients.id,
        name: clients.name,
        brand_name: clients.brand_name,
        token: clients.token,
        slug: clients.slug,
      })
      .from(clients)
      .where(eq(clients.token, tokenOrSlug))
      .limit(1);
  }

  if (clientRows.length === 0) return null;
  const client = clientRows[0];

  const projectRows = await db
    .select({ id: projects.id, name: projects.name, archived: projects.archived })
    .from(projects)
    .where(eq(projects.client_id, client.id))
    .orderBy(asc(projects.created_at));

  const activeProjects = projectRows.filter((p) => !p.archived);

  return { client, projects: activeProjects };
  } catch (err) {
    console.error("[client-view] getClientWithProjectsByToken error:", err);
    return null;
  }
}

/**
 * Returns full project data for the client dashboard.
 * CRITICAL: Does NOT include quote_items — client API never exposes them (CLAUDE.md constraint).
 * payments include status only, NOT amount or unit_price (DASH-07).
 */
export async function getProjectView(projectId: string): Promise<ProjectView | null> {
  const projectRows = await db
    .select({
      id: projects.id,
      name: projects.name,
      client_id: projects.client_id,
      accepted_total: projects.accepted_total,
    })
    .from(projects)
    .where(eq(projects.id, projectId))
    .limit(1);

  if (projectRows.length === 0) return null;
  const project = projectRows[0];

  const phasesRows = await db
    .select()
    .from(phases)
    .where(eq(phases.project_id, projectId))
    .orderBy(asc(phases.sort_order));

  const phaseIds = phasesRows.map((p) => p.id);

  const tasksRows =
    phaseIds.length === 0
      ? []
      : await db
          .select()
          .from(tasks)
          .where(inArray(tasks.phase_id, phaseIds))
          .orderBy(asc(tasks.sort_order));

  const taskIds = tasksRows.map((t) => t.id);

  // approved_at included — immutable audit trail (CLAUDE.md constraint LOCKED)
  const deliverablesRows =
    taskIds.length === 0
      ? []
      : await db
          .select({
            id: deliverables.id,
            title: deliverables.title,
            url: deliverables.url,
            status: deliverables.status,
            approved_at: deliverables.approved_at,
            task_id: deliverables.task_id,
          })
          .from(deliverables)
          .where(inArray(deliverables.task_id, taskIds));

  // Payments — status only, NO amount (DASH-07 / CLAUDE.md)
  const paymentsRows = await db
    .select({
      id: payments.id,
      label: payments.label,
      status: payments.status,
      // amount intentionally excluded — client API never exposes payment amounts
    })
    .from(payments)
    .where(eq(payments.project_id, projectId));

  const documentsRows = await db
    .select({
      id: documents.id,
      label: documents.label,
      url: documents.url,
      created_at: documents.created_at,
    })
    .from(documents)
    .where(eq(documents.project_id, projectId))
    .orderBy(asc(documents.created_at));

  const notesRows = await db
    .select({ id: notes.id, body: notes.body, created_at: notes.created_at })
    .from(notes)
    .where(eq(notes.project_id, projectId))
    .orderBy(asc(notes.created_at));

  // Fetch active offers for this project (client-safe fields only — never internal_name)
  const projectOfferRows = await db
    .select({
      id: project_offers.id,
      public_name: offer_micros.public_name,   // EXPLICITLY public_name, never internal_name
      accepted_total: project_offers.accepted_total,
      micro_id: project_offers.micro_id,
    })
    .from(project_offers)
    .innerJoin(offer_micros, eq(project_offers.micro_id, offer_micros.id))
    .where(eq(project_offers.project_id, projectId));

  // Cumulative price per micro (sum of assigned services)
  const microIds = projectOfferRows.map((o) => o.micro_id);
  const cumulativePriceRows = microIds.length === 0 ? [] : await db
    .select({
      micro_id: offer_micro_services.micro_id,
      cumulative_price: sql<string>`coalesce(sum(${offer_services.price}::numeric), 0)`,
    })
    .from(offer_micro_services)
    .innerJoin(offer_services, eq(offer_micro_services.service_id, offer_services.id))
    .where(inArray(offer_micro_services.micro_id, microIds))
    .groupBy(offer_micro_services.micro_id);

  const cumulMap = new Map(cumulativePriceRows.map((r) => [r.micro_id, r.cumulative_price]));

  const activeOffers = projectOfferRows.map((o) => ({
    id: o.id,
    public_name: o.public_name,
    cumulative_price: cumulMap.get(o.micro_id) ?? "0",
    accepted_total: o.accepted_total ? String(o.accepted_total) : null,
  }));

  // Comments scoped to tasks and deliverables of this project
  const allEntityIds = [...taskIds, ...deliverablesRows.map((d) => d.id)];
  const commentsRows =
    allEntityIds.length === 0
      ? []
      : await db
          .select()
          .from(comments)
          .where(inArray(comments.entity_id, allEntityIds))
          .orderBy(asc(comments.created_at));

  const phasesWithTasks = phasesRows.map((phase) => {
    const phaseTasks = tasksRows
      .filter((t) => t.phase_id === phase.id)
      .map((task) => ({
        ...task,
        deliverables: deliverablesRows.filter((d) => d.task_id === task.id),
      }));

    const doneCount = phaseTasks.filter((t) => t.status === "done").length;
    const progress_pct =
      phaseTasks.length > 0 ? Math.round((doneCount / phaseTasks.length) * 100) : 0;

    return { ...phase, tasks: phaseTasks, progress_pct };
  });

  const doneTasks = tasksRows.filter((t) => t.status === "done").length;
  const global_progress_pct =
    tasksRows.length > 0 ? Math.round((doneTasks / tasksRows.length) * 100) : 0;

  return {
    project: {
      id: project.id,
      name: project.name,
      client_id: project.client_id,
      accepted_total: project.accepted_total ?? "0",
    },
    phases: phasesWithTasks,
    payments: paymentsRows,
    documents: documentsRows,
    notes: notesRows,
    comments: commentsRows,
    global_progress_pct,
    activeOffers: activeOffers.length > 0 ? activeOffers : undefined,
  };
}