"use client";
import { useState, useMemo } from "react";
import {
  Search,
  ZoomIn,
  ZoomOut,
  Maximize2,
  Building2,
  Shield,
  Star,
  Users,
  ChevronDown,
  ChevronRight,
  Network,
  LayoutGrid,
  List,
  Cloud,
  Printer,
  Phone,
  MousePointerClick,
} from "lucide-react";
import { cn, getInitials } from "@/lib/utils";
import Avatar from "./ui/Avatar";
import Badge from "./ui/Badge";
import EmployeeProfileModal from "./EmployeeProfileModal";

/** Photo-aware avatar that falls back to coloured initials. */
function PersonAvatar({
  employee,
  size = "sm",
}: {
  employee: { firstName: string; lastName: string; avatarColor: string | null; photoUrl?: string | null };
  size?: "xs" | "sm" | "md" | "lg";
}) {
  const px = { xs: 24, sm: 32, md: 40, lg: 48 }[size];
  if (employee.photoUrl) {
    return (
      // eslint-disable-next-line @next/next/no-img-element
      <img
        src={employee.photoUrl}
        alt={`${employee.firstName} ${employee.lastName}`}
        width={px}
        height={px}
        style={{ width: px, height: px }}
        className="rounded-full object-cover flex-shrink-0 bg-slate-100"
      />
    );
  }
  return (
    <Avatar
      firstName={employee.firstName}
      lastName={employee.lastName}
      color={employee.avatarColor ?? "#3B82F6"}
      size={size}
    />
  );
}

interface OrgNode {
  id: number;
  parentId: number | null;
  name: string;
  type: string;
  color: string | null;
  sortOrder: number | null;
  externalSource?: string;
  isManaged?: boolean;
}

interface Employee {
  id: number;
  firstName: string;
  lastName: string;
  rank: string | null;
  role: string;
  orgNodeId: number | null;
  avatarColor: string | null;
  badgeNumber: string | null;
  jobTitle?: string | null;
  isActive?: boolean | null;
  externalSource?: string;
  photoUrl?: string | null;
  mobilePhone?: string | null;
}

interface Props {
  nodes: OrgNode[];
  employees: Employee[];
  departmentName: string;
  actorId: number | null;
  onEmployeeUpdated?: () => void;
}

type ViewMode = "tree" | "hierarchy" | "directory";
type Scope = "all" | number;

const ICONS: Record<string, React.ElementType> = {
  department: Building2,
  district: Shield,
  squad: Star,
  unit: Users,
  position: Users,
};

const ROLE_COLOR: Record<string, string> = {
  admin: "#EF4444",
  supervisor: "#F59E0B",
  officer: "#3B82F6",
};

export default function OrgChartViewer({
  nodes,
  employees,
  departmentName,
  actorId,
  onEmployeeUpdated,
}: Props) {
  const [selectedId, setSelectedId] = useState<number | null>(null);
  const [view, setView] = useState<ViewMode>("hierarchy");
  const [scope, setScope] = useState<Scope>("all");
  const [zoom, setZoom] = useState(1);
  const [search, setSearch] = useState("");
  const [collapsed, setCollapsed] = useState<Set<number>>(new Set());
  const [showVacant, setShowVacant] = useState(true);

  const activeEmployees = useMemo(() => employees.filter((e) => e.isActive !== false), [employees]);

  // Scope narrows the whole tree down to one branch
  const scopedNodes = useMemo(() => {
    if (scope === "all") return nodes;
    const keep = new Set<number>([scope]);
    let grew = true;
    while (grew) {
      grew = false;
      for (const n of nodes) {
        if (n.parentId !== null && keep.has(n.parentId) && !keep.has(n.id)) {
          keep.add(n.id);
          grew = true;
        }
      }
    }
    return nodes.filter((n) => keep.has(n.id));
  }, [nodes, scope]);

  const matches = (e: Employee) =>
    search.trim() === "" ||
    `${e.firstName} ${e.lastName} ${e.rank ?? ""} ${e.badgeNumber ?? ""} ${e.jobTitle ?? ""}`
      .toLowerCase()
      .includes(search.toLowerCase());

  const nodeMatches = (n: OrgNode) =>
    search.trim() === "" || n.name.toLowerCase().includes(search.toLowerCase());

  const childrenOf = (id: number | null) =>
    scopedNodes
      .filter((n) => n.parentId === id)
      .sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0) || a.id - b.id);

  const staffOf = (id: number) => activeEmployees.filter((e) => e.orgNodeId === id);

  const totalUnder = (id: number): number => {
    let count = staffOf(id).length;
    for (const c of childrenOf(id)) count += totalUnder(c.id);
    return count;
  };

  const roots = scope === "all" ? childrenOf(null) : scopedNodes.filter((n) => n.id === scope);

  const toggle = (id: number) =>
    setCollapsed((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });

  const stats = useMemo(() => {
    const supervisors = activeEmployees.filter((e) => e.role === "supervisor" || e.role === "admin").length;
    const synced = activeEmployees.filter((e) => e.externalSource && e.externalSource !== "manual").length;
    return {
      people: activeEmployees.length,
      units: scopedNodes.length,
      supervisors,
      unassigned: activeEmployees.filter((e) => e.orgNodeId === null).length,
      synced,
    };
  }, [activeEmployees, scopedNodes]);

  // ------------------------------------------------------------ card
  const NodeCard = ({ node, compact }: { node: OrgNode; compact?: boolean }) => {
    const Icon = ICONS[node.type] ?? Users;
    const staff = staffOf(node.id);
    const lead = staff.find((s) => s.role === "supervisor" || s.role === "admin");
    const color = node.color ?? "#3B82F6";
    const dim = search.trim() !== "" && !nodeMatches(node) && !staff.some(matches);

    return (
      <div
        className={cn(
          "rounded-xl border bg-white shadow-sm transition-opacity",
          dim ? "opacity-30" : "opacity-100",
          compact ? "min-w-[180px]" : "min-w-[220px]"
        )}
        style={{ borderTop: `3px solid ${color}` }}
      >
        <div className="p-3">
          <div className="flex items-center gap-2 mb-1">
            <div
              className="w-7 h-7 rounded-lg flex items-center justify-center flex-shrink-0"
              style={{ backgroundColor: `${color}22`, color }}
            >
              <Icon size={14} />
            </div>
            <div className="min-w-0 flex-1">
              <p className="text-sm font-bold text-slate-800 truncate">{node.name}</p>
              <p className="text-[10px] uppercase tracking-wide text-slate-400">{node.type}</p>
            </div>
          </div>

          {lead && (
            <button
              onClick={() => setSelectedId(lead.id)}
              className="w-full flex items-center gap-1.5 mt-2 pt-2 border-t border-slate-100 hover:bg-slate-50 rounded-lg -mx-1 px-1 py-0.5 transition-colors text-left"
              title={`View ${lead.firstName} ${lead.lastName}'s profile`}
            >
              <PersonAvatar employee={lead} size="xs" />
              <div className="min-w-0">
                <p className="text-[11px] font-semibold text-slate-700 truncate">
                  {lead.firstName} {lead.lastName}
                </p>
                <p className="text-[10px] text-slate-400 truncate">{lead.rank}</p>
              </div>
            </button>
          )}

          <div className="flex items-center gap-2 mt-2">
            <Badge color={color}>{staff.length} direct</Badge>
            {totalUnder(node.id) !== staff.length && (
              <span className="text-[10px] text-slate-400">{totalUnder(node.id)} total</span>
            )}
          </div>

          {!compact && staff.length > 0 && (
            <div className="flex flex-wrap gap-1 mt-2">
              {staff.slice(0, 8).map((s) => (
                <button
                  key={s.id}
                  onClick={() => setSelectedId(s.id)}
                  title={`${s.firstName} ${s.lastName} — ${s.rank ?? s.role}`}
                  className={cn(
                    "transition-all hover:scale-110 hover:ring-2 hover:ring-blue-400 rounded-full",
                    search && !matches(s) ? "opacity-25" : ""
                  )}
                >
                  <PersonAvatar employee={s} size="xs" />
                </button>
              ))}
              {staff.length > 8 && (
                <span className="text-[10px] text-slate-400 self-center">+{staff.length - 8}</span>
              )}
            </div>
          )}
        </div>
      </div>
    );
  };

  // ------------------------------------------------------------ hierarchy (top-down)
  const HierarchyBranch = ({ node }: { node: OrgNode }) => {
    const kids = childrenOf(node.id);
    const isCollapsed = collapsed.has(node.id);
    return (
      <div className="flex flex-col items-center">
        <div className="relative">
          <NodeCard node={node} compact />
          {kids.length > 0 && (
            <button
              onClick={() => toggle(node.id)}
              className="absolute -bottom-2.5 left-1/2 -translate-x-1/2 w-5 h-5 rounded-full bg-white border border-slate-300 flex items-center justify-center text-slate-500 hover:border-blue-400 hover:text-blue-500 shadow-sm z-10"
            >
              {isCollapsed ? <ChevronRight size={11} /> : <ChevronDown size={11} />}
            </button>
          )}
        </div>

        {kids.length > 0 && !isCollapsed && (
          <>
            <div className="w-px h-6 bg-slate-300" />
            <div className="relative flex gap-6">
              {kids.length > 1 && (
                <div
                  className="absolute top-0 h-px bg-slate-300"
                  style={{ left: "12%", right: "12%" }}
                />
              )}
              {kids.map((child) => (
                <div key={child.id} className="flex flex-col items-center">
                  <div className="w-px h-6 bg-slate-300" />
                  <HierarchyBranch node={child} />
                </div>
              ))}
            </div>
          </>
        )}
      </div>
    );
  };

  // ------------------------------------------------------------ indented tree
  const TreeRow = ({ node, depth }: { node: OrgNode; depth: number }) => {
    const kids = childrenOf(node.id);
    const isCollapsed = collapsed.has(node.id);
    const Icon = ICONS[node.type] ?? Users;
    const staff = staffOf(node.id);
    const color = node.color ?? "#3B82F6";
    const dim = search.trim() !== "" && !nodeMatches(node) && !staff.some(matches);

    return (
      <div>
        <div
          className={cn(
            "flex items-center gap-2 py-2 px-3 rounded-lg hover:bg-slate-50 transition-colors",
            dim && "opacity-30"
          )}
          style={{ marginLeft: depth * 24 }}
        >
          <button
            onClick={() => toggle(node.id)}
            className={cn("text-slate-400 hover:text-slate-700", kids.length === 0 && "invisible")}
          >
            {isCollapsed ? <ChevronRight size={14} /> : <ChevronDown size={14} />}
          </button>
          <div
            className="w-6 h-6 rounded-md flex items-center justify-center flex-shrink-0"
            style={{ backgroundColor: `${color}22`, color }}
          >
            <Icon size={12} />
          </div>
          <span className="text-sm font-semibold text-slate-800">{node.name}</span>
          <Badge color={color}>{node.type}</Badge>
          <span className="text-xs text-slate-400">
            {staff.length} direct · {totalUnder(node.id)} total
          </span>
          <div className="flex -space-x-1.5 ml-auto">
            {staff.slice(0, 6).map((s) => (
              <button
                key={s.id}
                onClick={() => setSelectedId(s.id)}
                className="ring-2 ring-white rounded-full hover:ring-blue-400 hover:z-10 hover:scale-110 transition-all"
                title={`${s.firstName} ${s.lastName} — view profile`}
              >
                <PersonAvatar employee={s} size="xs" />
              </button>
            ))}
          </div>
        </div>
        {!isCollapsed && kids.map((c) => <TreeRow key={c.id} node={c} depth={depth + 1} />)}
      </div>
    );
  };

  // ------------------------------------------------------------ directory
  const DirectoryView = () => {
    const grouped = scopedNodes
      .map((n) => ({ node: n, staff: staffOf(n.id).filter(matches) }))
      .filter((g) => g.staff.length > 0 || (showVacant && nodeMatches(g.node)));
    const unassigned = activeEmployees.filter((e) => e.orgNodeId === null && matches(e));

    return (
      <div className="space-y-4">
        {grouped.map(({ node, staff }) => (
          <div key={node.id} className="rounded-xl border border-slate-200 overflow-hidden">
            <div
              className="px-4 py-2.5 flex items-center gap-2"
              style={{ backgroundColor: `${node.color ?? "#3B82F6"}18` }}
            >
              <span className="w-2.5 h-2.5 rounded-full" style={{ backgroundColor: node.color ?? "#3B82F6" }} />
              <span className="font-semibold text-sm text-slate-800">{node.name}</span>
              <Badge color={node.color ?? "#3B82F6"}>{node.type}</Badge>
              <span className="text-xs text-slate-500 ml-auto">{staff.length} assigned</span>
            </div>
            {staff.length > 0 ? (
              <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2 p-3">
                {staff.map((e) => (
                  <button
                    key={e.id}
                    onClick={() => setSelectedId(e.id)}
                    className="flex items-center gap-2.5 p-2 rounded-lg bg-slate-50 hover:bg-blue-50 hover:ring-1 hover:ring-blue-300 transition-all text-left"
                  >
                    <PersonAvatar employee={e} size="sm" />
                    <div className="min-w-0 flex-1">
                      <p className="text-sm font-semibold text-slate-800 truncate">
                        {e.firstName} {e.lastName}
                      </p>
                      <p className="text-xs text-slate-400 truncate">
                        {e.rank ?? e.jobTitle} {e.badgeNumber ? `· #${e.badgeNumber}` : ""}
                      </p>
                    </div>
                    {e.mobilePhone && (
                      <span
                        role="link"
                        tabIndex={0}
                        onClick={(ev) => {
                          ev.stopPropagation();
                          window.location.href = `tel:${e.mobilePhone?.replace(/[^\d+]/g, "")}`;
                        }}
                        onKeyDown={(ev) => ev.stopPropagation()}
                        className="p-1.5 rounded-lg bg-green-100 text-green-600 hover:bg-green-200 cursor-pointer"
                        title={`Call ${e.mobilePhone}`}
                      >
                        <Phone size={13} />
                      </span>
                    )}
                    <Badge color={ROLE_COLOR[e.role] ?? "#3B82F6"}>{e.role}</Badge>
                  </button>
                ))}
              </div>
            ) : (
              <p className="text-xs text-slate-400 italic p-3">No officers assigned</p>
            )}
          </div>
        ))}
        {unassigned.length > 0 && (
          <div className="rounded-xl border border-dashed border-amber-300 bg-amber-50 p-3">
            <p className="text-sm font-semibold text-amber-700 mb-2">Unassigned ({unassigned.length})</p>
            <div className="flex flex-wrap gap-2">
              {unassigned.map((e) => (
                <button
                  key={e.id}
                  onClick={() => setSelectedId(e.id)}
                  className="flex items-center gap-2 bg-white rounded-lg px-2 py-1 border border-amber-200 hover:border-blue-400 transition-colors"
                >
                  <PersonAvatar employee={e} size="xs" />
                  <span className="text-xs font-medium text-slate-700">
                    {e.firstName} {e.lastName}
                  </span>
                </button>
              ))}
            </div>
          </div>
        )}
      </div>
    );
  };

  return (
    <div>
      {/* Controls */}
      <div className="flex flex-wrap items-center gap-3 mb-5">
        {/* Scope selector — the whole organization or one branch */}
        <div className="flex items-center gap-2">
          <Network size={15} className="text-slate-400" />
          <select
            value={scope === "all" ? "all" : String(scope)}
            onChange={(e) => setScope(e.target.value === "all" ? "all" : parseInt(e.target.value))}
            className="border border-slate-200 rounded-xl px-3 py-2 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-blue-500 max-w-[260px]"
          >
            <option value="all">🏛 Entire Organization — {departmentName}</option>
            {nodes
              .filter((n) => n.parentId === null)
              .map((n) => (
                <optgroup key={n.id} label={n.name}>
                  <option value={n.id}>{n.name} (whole branch)</option>
                  {nodes
                    .filter((c) => c.parentId === n.id)
                    .map((c) => (
                      <option key={c.id} value={c.id}>
                        &nbsp;&nbsp;↳ {c.name}
                      </option>
                    ))}
                </optgroup>
              ))}
          </select>
        </div>

        {/* View mode */}
        <div className="flex bg-slate-100 rounded-xl p-1">
          {(
            [
              ["hierarchy", "Chart", LayoutGrid],
              ["tree", "Tree", Network],
              ["directory", "Directory", List],
            ] as const
          ).map(([mode, label, Icon]) => (
            <button
              key={mode}
              onClick={() => setView(mode)}
              className={cn(
                "flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm font-medium transition-colors",
                view === mode ? "bg-white text-blue-600 shadow-sm" : "text-slate-500 hover:text-slate-700"
              )}
            >
              <Icon size={14} />
              {label}
            </button>
          ))}
        </div>

        {/* Search */}
        <div className="relative flex-1 min-w-[180px]">
          <Search size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" />
          <input
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder="Find an officer or unit…"
            className="w-full pl-9 pr-3 py-2 border border-slate-200 rounded-xl text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
          />
        </div>

        {view === "hierarchy" && (
          <div className="flex items-center gap-1 bg-slate-100 rounded-xl p-1">
            <button onClick={() => setZoom((z) => Math.max(0.4, z - 0.1))} className="p-1.5 rounded-lg hover:bg-white">
              <ZoomOut size={15} />
            </button>
            <span className="text-xs font-medium text-slate-600 w-10 text-center">{Math.round(zoom * 100)}%</span>
            <button onClick={() => setZoom((z) => Math.min(1.5, z + 0.1))} className="p-1.5 rounded-lg hover:bg-white">
              <ZoomIn size={15} />
            </button>
            <button onClick={() => setZoom(1)} className="p-1.5 rounded-lg hover:bg-white" title="Reset zoom">
              <Maximize2 size={14} />
            </button>
          </div>
        )}

        <button
          onClick={() => setCollapsed(new Set())}
          className="px-3 py-2 border border-slate-200 rounded-xl text-sm text-slate-600 hover:bg-slate-50"
        >
          Expand all
        </button>
        <button
          onClick={() => window.print()}
          className="p-2 border border-slate-200 rounded-xl text-slate-500 hover:bg-slate-50"
          title="Print / export"
        >
          <Printer size={15} />
        </button>
      </div>

      {/* Stats bar */}
      <div className="grid grid-cols-2 sm:grid-cols-5 gap-3 mb-5">
        {[
          { label: "Personnel", value: stats.people, color: "#3B82F6" },
          { label: "Units", value: stats.units, color: "#8B5CF6" },
          { label: "Supervisors", value: stats.supervisors, color: "#F59E0B" },
          { label: "Unassigned", value: stats.unassigned, color: "#EF4444" },
          { label: "Directory-synced", value: stats.synced, color: "#10B981" },
        ].map((s) => (
          <div key={s.label} className="rounded-xl border border-slate-200 bg-white p-3">
            <div className="text-xl font-bold" style={{ color: s.color }}>
              {s.value}
            </div>
            <div className="text-[11px] text-slate-500">{s.label}</div>
          </div>
        ))}
      </div>

      {/* Canvas */}
      <div
        className={cn(
          "rounded-2xl border border-slate-200 bg-slate-50/60",
          view === "hierarchy" ? "overflow-auto p-8" : "p-4"
        )}
      >
        {roots.length === 0 && (
          <div className="text-center py-14 text-slate-400">
            <Building2 size={36} className="mx-auto mb-3 opacity-40" />
            <p className="font-medium">Nothing to display</p>
            <p className="text-sm">Build your org chart or run a directory sync.</p>
          </div>
        )}

        {view === "hierarchy" && roots.length > 0 && (
          <div
            className="flex gap-10 justify-center items-start min-w-max mx-auto origin-top"
            style={{ transform: `scale(${zoom})` }}
          >
            {roots.map((r) => (
              <HierarchyBranch key={r.id} node={r} />
            ))}
          </div>
        )}

        {view === "tree" && roots.map((r) => <TreeRow key={r.id} node={r} depth={0} />)}
        {view === "directory" && <DirectoryView />}
      </div>

      <div className="mt-3 space-y-1">
        <p className="text-xs text-slate-500 flex items-center gap-1.5">
          <MousePointerClick size={12} />
          Click any officer to open their profile card with click-to-call and click-to-text contacts.
        </p>
        <p className="text-xs text-slate-400 flex items-center gap-1.5">
          <Cloud size={12} />
          Units and officers sourced from Active Directory / Munis are kept in step automatically; use the Org Chart
          tab to make structural changes.
        </p>
      </div>

      <EmployeeProfileModal
        employeeId={selectedId}
        actorId={actorId}
        onClose={() => setSelectedId(null)}
        onSaved={onEmployeeUpdated}
      />
    </div>
  );
}
