"use client";

import * as React from "react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { useSession } from "next-auth/react";
import { useDispatch, useSelector } from "react-redux";
import { ChevronLeft, Loader2, UserPlus, X } from "lucide-react";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import {
  useGetAllUsersQuery,
  useGetRolesQuery,
  useGetPipelinesQuery,
} from "@/api/rtk";
import { useGetTeamsQuery } from "@/api/rtk/teams-api";
import { useGetDealsQuery, type Deal } from "@/api/rtk/deals-api";
import { useGetProfileQuery } from "@/api/rtk/auth-api";
import { useAuthToken } from "@/hooks/use-auth-token";
import { hasPermission } from "@/lib/permissions";
import {
  selectBulkAssignLeads,
  clearBulkAssignSelection,
  removeBulkAssignSelectionItem,
} from "@/store";
import { pickRoleIdFromOrgRoles } from "@/components/deals/contributor-user-picker";
import {
  BulkAssignFields,
  buildBulkAssignPayload,
  emptyBulkAssignFieldsValue,
  hasBulkAssignChanges,
  type BulkAssignFieldsValue,
} from "@/components/deals/bulk-assign-fields";
import { useBulkAssignLeadsMutation } from "@/features/leads/hooks/use-bulk-assign-leads-mutation";
import { formatTeamLabelForUi } from "../../lib/deal-display";
import { flattenPipelineStages } from "@/lib/deal-stage-labels";
import type { BulkAssignLeadsResult } from "@/features/leads/types";
import type { BulkAssignLeadRow } from "@/store/slices/bulk-assign-leads-slice";
import { ForbiddenView, EmptyState } from "./bulk-assign-views";

export function BulkAssignLeadsPage() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const dispatch = useDispatch();
  const { data: session } = useSession();
  const { token } = useAuthToken();
  const { data: profile } = useGetProfileQuery(undefined, { skip: !token });

  const idsParam = searchParams.get("ids");
  const { data: fetchedDeals = [], isLoading: isLoadingDeals } = useGetDealsQuery(
    { ids: idsParam || "" },
    { skip: !idsParam },
  );

  const reduxSelectedLeads = useSelector(selectBulkAssignLeads);

  const permissionSource = React.useMemo(
    () =>
      (session as { backendUser?: unknown } | null)?.backendUser ?? profile,
    [session, profile],
  );

  const canBulkAssignLead = React.useMemo(
    () => hasPermission(permissionSource, "UPDATE", "BULK_ASSIGN_LEAD"),
    [permissionSource],
  );

  const { data: pipelines = [] } = useGetPipelinesQuery(undefined, { skip: !idsParam });

  const pipelineMap = React.useMemo(() => {
    const map = new Map<string, string>();
    for (const p of pipelines) {
      if (p.id) map.set(p.id, p.name || p.id);
    }
    return map;
  }, [pipelines]);

  const stageMap = React.useMemo(() => {
    const map = new Map<string, string>();
    for (const p of pipelines) {
      if (p.stages) {
        const flat = flattenPipelineStages(p.stages);
        for (const s of flat) {
          map.set(s.id, s.name);
        }
      }
    }
    return map;
  }, [pipelines]);

  const selectedLeads = React.useMemo(() => {
    if (!idsParam) return reduxSelectedLeads;
    return fetchedDeals.map(
      (d: Deal): BulkAssignLeadRow => ({
        id: d.id,
        customerName: d.customerName ?? null,
        pipelineId: d.pipelineId,
        pipelineName: pipelineMap.get(d.pipelineId) || d.pipelineId,
        stage: d.stage,
        stageName: d.stageDetail?.stageName?.name || stageMap.get(d.stage) || d.stage,
        team: d.team ?? null,
        ownerId: d.ownerId ?? d.owner?.id,
        ownerName: d.owner?.name,
        aeIds: d.aeIds ?? [],
        bdrIds: d.bdrIds ?? [],
        contributorIds: d.contributorIds ?? [],
        updatedAt: d.updatedAt,
        isAlreadyAssigned: (d.aeIds?.length ?? 0) > 0 || (d.bdrIds?.length ?? 0) > 0,
      }),
    );
  }, [idsParam, fetchedDeals, reduxSelectedLeads, pipelineMap, stageMap]);

  const commonTeam = React.useMemo(() => {
    if (selectedLeads.length === 0) return undefined;
    const firstTeam = selectedLeads[0].team;
    const allSame = selectedLeads.every((l: BulkAssignLeadRow) => l.team === firstTeam);
    if (allSame) {
      return firstTeam ? formatTeamLabelForUi(firstTeam) : "None";
    }
    return "Mixed";
  }, [selectedLeads]);

  const [value, setValue] = React.useState<BulkAssignFieldsValue>(
    emptyBulkAssignFieldsValue,
  );
  const [lastResult, setLastResult] =
    React.useState<BulkAssignLeadsResult | null>(null);

  const { data: teams = [] } = useGetTeamsQuery(undefined, {
    skip: !canBulkAssignLead || selectedLeads.length === 0,
  });
  const { data: orgRoles = [] } = useGetRolesQuery(undefined, {
    skip: !canBulkAssignLead || !token || selectedLeads.length === 0,
  });
  const { data: allUsers = [] } = useGetAllUsersQuery(undefined, {
    skip: !canBulkAssignLead || !token || selectedLeads.length === 0,
  });

  const aeRoleId = React.useMemo(
    () => pickRoleIdFromOrgRoles(orgRoles, ["ae", "account executive"]),
    [orgRoles],
  );
  const bdrRoleId = React.useMemo(
    () =>
      pickRoleIdFromOrgRoles(orgRoles, [
        "bdr",
        "business development representative",
      ]),
    [orgRoles],
  );

  const labelById = React.useMemo(() => {
    const map: Record<string, string | undefined> = {};
    for (const u of allUsers) {
      map[u.id] = u.name || u.email || u.id;
    }
    for (const row of selectedLeads) {
      if (row.ownerId && row.ownerName && !map[row.ownerId]) {
        map[row.ownerId] = row.ownerName;
      }
    }
    return map;
  }, [allUsers, selectedLeads]);

  const assignmentPanelRef = React.useRef<HTMLElement>(null);

  const mutation = useBulkAssignLeadsMutation();
  const isPending = mutation.isPending;
  const canApply =
    selectedLeads.length > 0 && hasBulkAssignChanges(value) && !isPending;

  const handleRemoveOne = React.useCallback(
    (id: string) => {
      dispatch(removeBulkAssignSelectionItem(id));
    },
    [dispatch],
  );

  const resetBulkAssignPageState = React.useCallback(() => {
    dispatch(clearBulkAssignSelection());
    setValue(emptyBulkAssignFieldsValue);
    setLastResult(null);
  }, [dispatch]);

  const handleClearAll = React.useCallback(() => {
    resetBulkAssignPageState();
  }, [resetBulkAssignPageState]);

  const handleApply = async () => {
    if (!canApply) return;
    const payload = buildBulkAssignPayload(
      selectedLeads.map((l) => l.id),
      value,
    );
    try {
      const result = await mutation.mutateAsync(payload);
      const updated = result.updated ?? 0;
      const skipped = result.skipped ?? 0;
      if (skipped > 0) {
        toast.success(`${updated} updated · ${skipped} skipped`);
      } else {
        toast.success(`${updated} leads updated`);
      }
      resetBulkAssignPageState();
      router.replace("/leads");
    } catch (err) {
      const message =
        err instanceof Error
          ? err.message
          : "Failed to apply bulk assignment";
      toast.error(message);
    }
  };

  if (!canBulkAssignLead) {
    return <ForbiddenView />;
  }

  if (isLoadingDeals) {
    return (
      <div className="flex flex-col items-center justify-center min-h-[60vh] gap-4">
        <Loader2 className="animate-spin text-accent" size={32} />
        <p className="text-[14px] text-gray-500 font-['Lexend_Deca']">
          Fetching lead details...
        </p>
      </div>
    );
  }

  if (selectedLeads.length === 0) {
    // After a successful submit we land here — surface a quick summary if
    // we just applied something.
    if (lastResult) {
      return (
        <div className="flex flex-col items-center justify-center min-h-[60vh] p-8 text-center gap-3">
          <div className="size-12 rounded-2xl bg-accent/10 flex items-center justify-center">
            <UserPlus size={20} className="text-accent" />
          </div>
          <h1 className="text-[20px] font-extrabold font-['Lexend'] text-text">
            Bulk assignment applied
          </h1>
          <p className="text-[13px] text-gray-500 font-['Lexend_Deca']">
            {lastResult.updated} updated · {lastResult.skipped} skipped
          </p>
          <Link href="/leads">
            <Button size="sm" className="gap-1.5">
              <ChevronLeft size={13} /> Back to Leads
            </Button>
          </Link>
        </div>
      );
    }
    return <EmptyState />;
  }

  return (
    <div className="flex flex-col h-full gap-4 p-3 md:p-5 animate-in fade-in duration-500 overflow-hidden">
      <div className="flex flex-col gap-2">
        <nav className="text-[12px] font-medium text-gray-500 font-['Lexend_Deca'] flex items-center gap-1.5">
          <Link href="/leads" className="hover:text-accent">
            Leads
          </Link>
          <span>/</span>
          <span className="text-text font-bold">Bulk Assign</span>
        </nav>
        <div className="flex items-center justify-between gap-3 flex-wrap">
          <div>
            <h1 className="text-[22px] font-extrabold font-['Lexend'] text-text leading-tight">
              Bulk Lead Assignment
            </h1>
            <p className="text-[12px] text-gray-500 font-['Lexend_Deca'] mt-0.5">
              {selectedLeads.length}{" "}
              {selectedLeads.length === 1 ? "lead" : "leads"} selected · Existing assignments can be
              replaced or appended
            </p>
          </div>
          <div className="flex items-center gap-2">
            <Button
              variant="outline"
              size="sm"
              onClick={handleClearAll}
              disabled={isPending}
            >
              Clear selection
            </Button>
            <Button
              variant="ghost"
              size="sm"
              onClick={() => router.push("/leads")}
              disabled={isPending}
              className="gap-1.5"
            >
              <ChevronLeft size={13} /> Back to Leads
            </Button>
          </div>
        </div>
      </div>

      <div className="flex-1 min-h-0 grid grid-cols-1 lg:grid-cols-[minmax(0,1fr)_360px] gap-4 overflow-hidden">
        <section className="min-w-0 flex flex-col rounded-2xl border border-border/60 bg-white overflow-hidden">
          <header className="px-4 py-3 border-b border-border/40 bg-gray-50/50">
            <h2 className="text-[12px] font-bold uppercase tracking-wider text-gray-500 font-['Lexend_Deca']">
              Selected leads ({selectedLeads.length})
            </h2>
          </header>
          <div className="flex-1 min-h-0 overflow-auto scrollbar-themed p-4">
            <Table className="font-['Lexend_Deca']" variant="transparent">
              <TableHeader className="bg-gray-50/50 sticky top-0 z-10 border-b border-border/40">
                <TableRow className="hover:bg-transparent cursor-default">
                  <TableHead className="w-10">#</TableHead>
                  <TableHead>Name</TableHead>
                  <TableHead>Pipeline</TableHead>
                  <TableHead>Stage</TableHead>
                  <TableHead>Current Team</TableHead>
                  <TableHead>AE(s)</TableHead>
                  <TableHead>BDR(s)</TableHead>
                  <TableHead>Owner</TableHead>
                  <TableHead className="w-10" />
                </TableRow>
              </TableHeader>
              <TableBody>
                {selectedLeads.map((row, idx) => (
                  <TableRow
                    key={row.id}
                    className="border-b border-border/30 last:border-b-0 hover:bg-accent/5 cursor-default"
                  >
                    <TableCell className="text-gray-400">{idx + 1}</TableCell>
                    <TableCell className="font-semibold text-text">
                      <div className="flex flex-col gap-0.5">
                        <span>{row.customerName ?? "—"}</span>
                      </div>
                    </TableCell>
                    <TableCell className="text-gray-600">
                      {row.pipelineName ?? row.pipelineId ?? "—"}
                    </TableCell>
                    <TableCell className="text-gray-600">
                      {row.stageName ?? row.stage ?? "—"}
                    </TableCell>
                    <TableCell className="text-gray-600">
                      {row.team ? formatTeamLabelForUi(row.team) : "—"}
                    </TableCell>
                    <TableCell className="text-gray-600">
                      {(row.aeIds?.length ?? 0) > 0
                        ? (row.aeIds ?? [])
                            .map((id) => labelById[id] || id)
                            .join(", ")
                        : "—"}
                    </TableCell>
                    <TableCell className="text-gray-600">
                      {(row.bdrIds?.length ?? 0) > 0
                        ? (row.bdrIds ?? [])
                            .map((id) => labelById[id] || id)
                            .join(", ")
                        : "—"}
                    </TableCell>
                    <TableCell className="text-gray-600">
                      {row.ownerName ??
                        (row.ownerId ? labelById[row.ownerId] : "—") ??
                        "—"}
                    </TableCell>
                    <TableCell>
                      <button
                        type="button"
                        onClick={(e) => {
                          e.stopPropagation();
                          handleRemoveOne(row.id);
                        }}
                        disabled={isPending}
                        aria-label={`Remove ${
                          row.customerName ?? row.id
                        } from selection`}
                        className="size-7 inline-flex items-center justify-center rounded-md text-gray-400 hover:text-destructive hover:bg-destructive/10 disabled:opacity-50"
                      >
                        <X size={13} />
                      </button>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          </div>
          <footer className="shrink-0 px-4 py-3 border-t border-border/40 bg-white">
            <Button
              size="sm"
              onClick={handleApply}
              disabled={!canApply}
              className="w-full gap-1.5"
            >
              {isPending ? (
                <>
                  <Loader2 size={13} className="animate-spin" /> Applying…
                </>
              ) : (
                <>
                  <UserPlus size={13} /> Apply to {selectedLeads.length}{" "}
                  {selectedLeads.length === 1 ? "lead" : "leads"}
                </>
              )}
            </Button>
          </footer>
        </section>

        <aside
          ref={assignmentPanelRef}
          className="min-w-0 flex flex-col rounded-2xl border border-border/60 bg-white overflow-hidden transition-[box-shadow,border-color] duration-300"
        >
          <header className="px-4 py-3 border-b border-border/40 bg-gray-50/50">
            <h2 className="text-[12px] font-bold uppercase tracking-wider text-gray-500 font-['Lexend_Deca']">
              Assignment settings
            </h2>
            <p className="text-[11px] text-gray-500 font-['Lexend_Deca'] mt-1 font-normal normal-case tracking-normal">
              Changes apply to all {selectedLeads.length} selected leads.
            </p>
          </header>
          <div className="flex-1 min-h-0 overflow-y-auto scrollbar-themed p-4">
            <BulkAssignFields
              value={value}
              onChange={setValue}
              teams={teams}
              aeRoleId={aeRoleId}
              bdrRoleId={bdrRoleId}
              labelById={labelById}
              activeLeadTeamDisplay={commonTeam}
            />
          </div>
        </aside>
      </div>
    </div>
  );
}
