"use client";

// Projects data layer. Serves EITHER the local mock (when the Shell isn't
// configured — the polished demo keeps working) OR the live be-crm data door
// (crm.project.*), behind one interface so the component is mode-agnostic.
// Mirrors team-api.ts.
//
// Live contract (be-crm):
//   query  crm.project.list      { perPage }          -> { items: ProjectDTO[], meta }
//   cmd    crm.project.create    { name, status?, value?, address?, dueDate?, ... }
//   cmd    crm.project.setStatus { id, status }
//   cmd    crm.project.remove    { id }
//
// be-crm's Project model is generic (name/status/value/owner/address/dates) —
// it has no stage, job type, progress or health score. Those are mock-only
// fields (undefined in live mode); the Projects screen renders a leaner
// column set when `live` is true.

import { useCallback, useMemo, useState } from "react";
import { useAppShell, useQuery } from "@abe-kap/appshell-sdk/react";
import { isShellConfigured } from "./appshell";
import {
  collectionsFor, constructionLeads, pipelineLeads,
  type CollectionRecord, type ConstructionStatus,
} from "@/components/dashboard/projects-data";

export type UiCollectionRecord = CollectionRecord;

/* ---- UI-facing shapes ---------------------------------------------------- */

// "lead" / "archived" round out the mock's four (active/complete/stuck/followup)
// so every be-crm ProjectStatus has somewhere to map to.
export type UiProjectStatus = ConstructionStatus | "lead" | "archived";

export interface UiProject {
  id: string;
  name: string;
  address: string | null;
  status: UiProjectStatus;
  stage: string | null; // mock only
  jobType: string | null; // mock only
  agent: string;
  progress: number | null; // mock only
  health: number | null; // mock only
  value: number | null; // dollars
  dueDate: string | null;
  createdAgo: string | null; // mock pipeline leads only
  collections: UiCollectionRecord[] | null; // mock only — no billing backend yet
  isLead: boolean; // true → "Pipeline Leads" tab
}

export interface NewProjectInput {
  name: string;
  status: UiProjectStatus;
  value?: number; // dollars
}

export interface ProjectsData {
  live: boolean;
  loading: boolean;
  error: string | null;
  projects: UiProject[];
  create: (p: NewProjectInput) => Promise<void>;
  setStatus: (id: string, status: UiProjectStatus) => Promise<void>;
  remove: (id: string) => Promise<void>;
  refetch: () => void;
}

export const STATUS_LABEL: Record<UiProjectStatus, string> = {
  lead: "Lead", active: "Active", complete: "Complete", stuck: "Stuck", followup: "Follow-up", archived: "Archived",
};
export const STATUS_TONE: Record<UiProjectStatus, string> = {
  lead: "purple", active: "green", complete: "blue", stuck: "red", followup: "orange", archived: "muted",
};
// Quick-filter chips only cover the four "in-flight job" statuses (mirrors the design).
export const QUICK_FILTERS: UiProjectStatus[] = ["active", "complete", "stuck", "followup"];

/* ---- mock → UI ------------------------------------------------------------ */

function mockConstruction(c: (typeof constructionLeads)[number], index: number): UiProject {
  return {
    id: c.id, name: c.name, address: c.address, status: c.status, stage: c.stage, jobType: c.jobType,
    agent: c.agent, progress: c.progress, health: c.health, value: c.value, dueDate: null, createdAgo: null,
    collections: collectionsFor(c, index), isLead: false,
  };
}
function mockPipeline(p: (typeof pipelineLeads)[number]): UiProject {
  return {
    id: p.id, name: p.name, address: p.address, status: "lead", stage: p.stage, jobType: p.jobType,
    agent: p.agent, progress: null, health: null, value: null, dueDate: null, createdAgo: p.createdAgo,
    collections: [], isLead: true,
  };
}

/* ======================================================================== */
/* Mock implementation (no Shell configured)                                */
/* ======================================================================== */

let mockSeq = 1;

function useMockProjects(): ProjectsData {
  const [projects, setProjects] = useState<UiProject[]>(() => [
    ...constructionLeads.map(mockConstruction),
    ...pipelineLeads.map(mockPipeline),
  ]);

  const create = useCallback(async (p: NewProjectInput) => {
    const isLead = p.status === "lead";
    const next: UiProject = {
      id: `new_${mockSeq++}`, name: p.name, address: null, status: p.status,
      stage: isLead ? "New Inquiry" : "New Lead", jobType: null, agent: "Unassigned",
      progress: isLead ? null : 0, health: isLead ? null : 70, value: isLead ? null : (p.value ?? null),
      dueDate: null, createdAgo: isLead ? "Just now" : null, collections: [], isLead,
    };
    setProjects((l) => [next, ...l]);
  }, []);
  const setStatus = useCallback(async (id: string, status: UiProjectStatus) => {
    setProjects((l) => l.map((p) => (p.id === id ? { ...p, status, isLead: status === "lead" } : p)));
  }, []);
  const remove = useCallback(async (id: string) => { setProjects((l) => l.filter((p) => p.id !== id)); }, []);

  return { live: false, loading: false, error: null, projects, create, setStatus, remove, refetch: () => {} };
}

/* ======================================================================== */
/* Live implementation (be-crm data door)                                   */
/* ======================================================================== */

type BackendStatus = "lead" | "active" | "on_hold" | "won" | "lost" | "archived";
const BACKEND_TO_UI: Record<BackendStatus, UiProjectStatus> = {
  lead: "lead", active: "active", on_hold: "stuck", won: "complete", lost: "followup", archived: "archived",
};
const UI_TO_BACKEND: Record<UiProjectStatus, BackendStatus> = {
  lead: "lead", active: "active", stuck: "on_hold", complete: "won", followup: "lost", archived: "archived",
};

interface ProjectAddressDTO { line1?: string | null; city?: string | null; state?: string | null; postalCode?: string | null }
interface ProjectDTO {
  id: string; name: string; status: BackendStatus; ownerPrincipalId: string | null;
  value: number | null; address: ProjectAddressDTO | null; dueDate: string | null;
}
interface MemberRef { principalId: string; displayName: string | null; jobTitle: string | null }

const fmtAddress = (a: ProjectAddressDTO | null): string | null => {
  if (!a) return null;
  const cityState = [a.city, a.state].filter(Boolean).join(" ");
  const parts = [a.line1, [cityState, a.postalCode].filter(Boolean).join(" ")].filter(Boolean);
  return parts.length ? parts.join(", ") : null;
};

function useLiveProjects(): ProjectsData {
  const { sdk } = useAppShell();
  const listQ = useQuery<{ items: ProjectDTO[] }>("crm.project.list", { perPage: 100 });
  // Resolve ownerPrincipalId → a real name for the "Owner" column (crm.project.list
  // only returns the raw id).
  const membersQ = useQuery<{ items: MemberRef[] }>("crm.team.member.search", { perPage: 100 });

  const refetch = useCallback(() => { listQ.refetch(); membersQ.refetch(); }, [listQ, membersQ]);
  const cmd = useCallback(async (action: string, variables: Record<string, unknown>) => {
    await sdk.command(action, variables);
    refetch();
  }, [sdk, refetch]);

  const nameByPrincipal = useMemo(() => {
    const m = new Map<string, string>();
    for (const it of membersQ.data?.items ?? []) if (it.principalId) m.set(it.principalId, it.displayName || it.jobTitle || it.principalId);
    return m;
  }, [membersQ.data]);

  const projects: UiProject[] = useMemo(() => (listQ.data?.items ?? []).map((d) => ({
    id: d.id, name: d.name, address: fmtAddress(d.address),
    status: BACKEND_TO_UI[d.status] ?? "active",
    stage: null, jobType: null,
    agent: d.ownerPrincipalId ? (nameByPrincipal.get(d.ownerPrincipalId) ?? "Unassigned") : "Unassigned",
    progress: null, health: null,
    value: d.value != null ? d.value / 100 : null, // minor units → dollars
    dueDate: d.dueDate, createdAgo: null, collections: null, isLead: d.status === "lead",
  })), [listQ.data, nameByPrincipal]);

  return {
    live: true,
    loading: listQ.loading || membersQ.loading,
    error: (listQ.error ?? membersQ.error)?.message ?? null,
    projects,
    create: (p) => cmd("crm.project.create", {
      name: p.name, status: UI_TO_BACKEND[p.status],
      ...(p.value != null ? { value: Math.round(p.value * 100) } : {}),
    }),
    setStatus: (id, status) => cmd("crm.project.setStatus", { id, status: UI_TO_BACKEND[status] }),
    remove: (id) => cmd("crm.project.remove", { id }),
    refetch,
  };
}

/* ---- public hook: pick the implementation at module-config time --------- */

const SHELL = isShellConfigured();

export function useProjectsData(): ProjectsData {
  return SHELL ? useLiveProjects() : useMockProjects();
}
