import { api } from "@/services/api";
import type { ProfileResponse } from "@/types/profile";
import {
  Alert,
  Anchor,
  Badge,
  Box,
  Button,
  Card,
  Center,
  Container,
  Fieldset,
  FileButton,
  Group,
  Loader,
  Stack,
  Tabs,
  Text,
  ThemeIcon,
  Title,
} from "@mantine/core";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  AlertCircle,
  AlertTriangle,
  BadgeCheck,
  Briefcase,
  Building2,
  Clock,
  FileCheck,
  FileText,
  Globe,
  Layers,
  RefreshCw,
  ShieldCheck,
  UploadCloud,
  User,
  UserCheck,
  UserCog,
} from "lucide-react";
import { companiesService } from "@/services/companies.service";
import { fetchViewableFile } from "@/services/files.service";
import { useFileViewer } from "@edr/ui-common";
import { useCallback, useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
import useAuth from "@/hooks/useAuth";
import { rolesForCompanyType } from "./settings/companyRoles";
import TabAccount from "./settings/TabAccount";
import TabCompanyProfile from "./settings/TabCompanyProfile";
import TabContactPerson from "./settings/TabContactPerson";
import TabDocuments from "./settings/TabDocuments";
import TabGeneralManager from "./settings/TabGeneralManager";
import TabPowerOfAttorney from "./settings/TabPowerOfAttorney";

type SettingsTab =
  | "account"
  | "company"
  | "contact"
  | "gm"
  | "poa"
  | "documents";

/** A section is "incomplete" when its required fields aren't filled in yet. */
function tabIncomplete(tabId: SettingsTab, profile: ProfileResponse): boolean {
  switch (tabId) {
    case "company":
      return (
        !profile.companyEmail ||
        !profile.companyPhone ||
        !profile.companyAddress ||
        !profile.fanNumber
      );
    case "contact":
      return !profile.contactPersonName || !profile.contactPersonPhone;
    case "gm":
      return (
        !profile.generalManagerName ||
        !profile.generalManagerEmail ||
        !profile.generalManagerPhone
      );
    case "account":
    // Account fields live on the IAM user, not the company profile, and are
    // always populated (signup requires them) — nothing to nag about here.
    case "poa":
    case "documents":
      return false;
  }
}

const TABS: { id: SettingsTab; label: string; icon: React.ReactNode }[] = [
  { id: "account", label: "Account", icon: <UserCog size={16} /> },
  { id: "company", label: "Company", icon: <Building2 size={16} /> },
  { id: "contact", label: "Contact Person", icon: <User size={16} /> },
  { id: "gm", label: "General Manager", icon: <Briefcase size={16} /> },
  { id: "poa", label: "Power of Attorney", icon: <UserCheck size={16} /> },
  { id: "documents", label: "Documents", icon: <FileCheck size={16} /> },
];

/**
 * Polished identity banner shown above the editor tabs — company name, its
 * registered operating roles, location and verification status at a glance.
 */
function ProfileHeader({ profile }: { profile: ProfileResponse }) {
  const refByType = new Map(profile.companyProfiles.map((p) => [p.type, p]));
  const roleOptions = rolesForCompanyType(profile.companyType);
  // Only an approved role is a role the company actually operates as. A pending
  // one carries no reference yet, and must not read as granted.
  const activeRoles = roleOptions.filter(
    (o) => refByType.get(o.type)?.status === "active",
  );

  return (
    <Card
      padding="xl"
      radius="lg"
      style={{
        background:
          "linear-gradient(135deg, var(--mantine-color-edr-ink-6) 0%, var(--mantine-color-edr-ink-8, var(--mantine-color-edr-ink-6)) 100%)",
        position: "relative",
        overflow: "hidden",
      }}
    >
      <Box
        style={{ position: "absolute", top: -24, right: -16, opacity: 0.08 }}
      >
        <Building2 size={180} color="white" />
      </Box>

      <Group
        justify="space-between"
        align="flex-start"
        wrap="nowrap"
        style={{ position: "relative", zIndex: 1 }}
      >
        <Group gap="lg" align="center" wrap="nowrap">
          <ThemeIcon variant="white" color="edr-green" size={72} radius="lg">
            <Building2 size={36} />
          </ThemeIcon>
          <Stack gap={8}>
            <Group gap="sm" align="center">
              <Title order={1} size="h2" c="white">
                {profile.companyName}
              </Title>
              <Badge
                color="edr-green"
                variant="filled"
                leftSection={<BadgeCheck size={13} />}
              >
                Verified
              </Badge>
            </Group>

            {activeRoles.length > 0 ? (
              <Group gap="xs">
                {activeRoles.map((opt) => (
                  <Badge
                    key={opt.type}
                    variant="white"
                    color="edr-ink"
                    radius="sm"
                    size="lg"
                  >
                    {opt.label} · {refByType.get(opt.type)!.reference}
                  </Badge>
                ))}
              </Group>
            ) : (
              <Text c="gray.4" fw={500} tt="capitalize">
                {profile.companyType.replace(/_/g, " ")}
              </Text>
            )}

            <Group gap="lg" mt={4}>
              {profile.companyLocation && (
                <Group gap={6} c="gray.4">
                  <Globe size={15} />
                  <Text size="sm">{profile.companyLocation}</Text>
                </Group>
              )}
              {profile.tinNumber && (
                <Group gap={6} c="gray.4">
                  <ShieldCheck size={15} />
                  <Text size="sm" ff="monospace">
                    TIN {profile.tinNumber}
                  </Text>
                </Group>
              )}
            </Group>
          </Stack>
        </Group>
      </Group>
    </Card>
  );
}

export default function SettingsPage() {
  const queryClient = useQueryClient();
  const { user } = useAuth();
  const [searchParams, setSearchParams] = useSearchParams();
  const tab = (searchParams.get("tab") as SettingsTab) || "company";

  const setTab = useCallback(
    (t: SettingsTab) => {
      setSearchParams(
        (prev) => {
          const next = new URLSearchParams(prev);
          next.set("tab", t);
          return next;
        },
        { replace: true },
      );
    },
    [setSearchParams],
  );

  const profileQuery = useQuery(
    api.companies.getProfile.queryOptions({
      retry: false,
      refetchOnWindowFocus: false,
    }),
  );
  const profile = profileQuery.data;

  // Keep the cached company info in sync whenever the profile changes, so the
  // header (and the rest of the app) reflect edits immediately.
  useEffect(() => {
    if (profileQuery.dataUpdatedAt > 0) {
      queryClient.invalidateQueries({
        queryKey: api.companies.getInfo.queryKey(),
      });
    }
  }, [profileQuery.dataUpdatedAt, queryClient]);

  if (profileQuery.isPending) {
    return (
      <Center h="100%">
        <Loader color="edr-green" size="lg" />
      </Center>
    );
  }

  if (!profile) {
    return (
      <Container size="xl" px="lg" py="xl">
        <Card padding="xl" radius="lg">
          <Center>
            <Group gap="sm" c="edr-muted">
              <AlertCircle size={20} />
              <Text>No company profile found.</Text>
            </Group>
          </Center>
        </Card>
      </Container>
    );
  }

  const reviewStatus = profile.reviewStatus ?? null;
  const locked = reviewStatus === "pending";

  return (
    <Container size="xl" px="lg" py="xl">
      <Stack gap="xl">
        <ProfileHeader profile={profile} />

        <div>
          <Title order={2} size="h3">
            Account Settings
          </Title>
          <Text c="edr-muted" size="sm" mt={4}>
            Manage your company profile, personnel, and documents.
          </Text>
        </div>

        {reviewStatus === "pending" && (
          <Alert
            color="yellow"
            variant="light"
            icon={<Clock size={18} />}
            title="Changes submitted for review"
          >
            Your recent changes are awaiting administrator approval. Editing is
            disabled until the review is complete — you'll be notified once it's
            approved or if any changes are requested.
          </Alert>
        )}
        {reviewStatus === "rejected" && (
          <Alert
            color="red"
            variant="light"
            icon={<AlertTriangle size={18} />}
            title="Changes were not approved"
          >
            <Stack gap={4}>
              {profile.reviewNote && (
                <Text size="sm">
                  <strong>Reviewer note:</strong> {profile.reviewNote}
                </Text>
              )}
              <Text size="sm">
                Please update the details below and save again to resubmit for
                review.
              </Text>
            </Stack>
          </Alert>
        )}

        <Tabs
          value={tab}
          onChange={(value) => value && setTab(value as SettingsTab)}
          variant="pills"
          radius="md"
        >
          <Tabs.List mb="lg">
            {TABS.map((t) => (
              <Tabs.Tab
                key={t.id}
                value={t.id}
                leftSection={t.icon}
                rightSection={
                  tabIncomplete(t.id, profile) ? (
                    <Box
                      w={7}
                      h={7}
                      style={{
                        borderRadius: "50%",
                        background: "var(--mantine-color-red-6)",
                      }}
                    />
                  ) : undefined
                }
              >
                {t.label}
              </Tabs.Tab>
            ))}
          </Tabs.List>

          {/* Deliberately NOT wrapped in the `locked` fieldset below: that lock
              is for company-profile edits awaiting review. Account identity is
              the user's own login/notification details — they must stay editable
              even mid-review, or a customer whose phone changed while pending
              would be locked out of their own OTPs. */}
          <Tabs.Panel value="account">
            {user ? (
              <TabAccount user={user} />
            ) : (
              <Center py="xl">
                <Loader color="edr-green" />
              </Center>
            )}
          </Tabs.Panel>

          {/* While a change request is pending, every panel's inputs + submit
              buttons are disabled via the native fieldset; tab switching stays
              enabled so the customer can still review what they submitted. */}
          <Tabs.Panel value="company">
            <Fieldset disabled={locked} variant="unstyled" p={0}>
              <TabCompanyProfile mode="edit" profile={profile} />
            </Fieldset>
            <OperationalServicesCard profile={profile} />
          </Tabs.Panel>
          <Tabs.Panel value="contact">
            <Fieldset disabled={locked} variant="unstyled" p={0}>
              <TabContactPerson profile={profile} mode="edit" />
            </Fieldset>
          </Tabs.Panel>
          <Tabs.Panel value="gm">
            <Fieldset disabled={locked} variant="unstyled" p={0}>
              <TabGeneralManager profile={profile} mode="edit" />
            </Fieldset>
          </Tabs.Panel>
          <Tabs.Panel value="poa">
            <Fieldset disabled={locked} variant="unstyled" p={0}>
              <TabPowerOfAttorney profile={profile} mode="edit" />
            </Fieldset>
          </Tabs.Panel>
          <Tabs.Panel value="documents">
            <Fieldset disabled={locked} variant="unstyled" p={0}>
              <TabDocuments profile={profile} mode="edit" />
            </Fieldset>
          </Tabs.Panel>
        </Tabs>
      </Stack>
    </Container>
  );
}

const ROLE_LABELS: Record<string, string> = {
  importer: "Importer",
  exporter: "Exporter",
  freight_forwarder: "Freight Forwarder",
  dj_freight_forwarder: "DJ Freight Forwarder",
  transporter: "Transporter",
};

const ROLE_STATUS: Record<string, { color: string; label: string }> = {
  active: { color: "edr-green", label: "Approved" },
  pending: { color: "yellow", label: "Awaiting approval" },
  rejected: { color: "red", label: "Rejected" },
  suspended: { color: "orange", label: "Suspended" },
  blacklisted: { color: "red", label: "Blocked" },
};

/**
 * Lists the company's operational services with approval status, and lets the
 * customer resubmit a rejected one — replacing its license first if the reviewer
 * flagged the document.
 */
function OperationalServicesCard({ profile }: { profile: ProfileResponse }) {
  const queryClient = useQueryClient();
  const { view, viewer } = useFileViewer();
  const roles = profile.companyProfiles;

  const refresh = () =>
    Promise.all([
      queryClient.invalidateQueries({
        queryKey: api.companies.getProfile.queryKey(),
      }),
      queryClient.invalidateQueries({
        queryKey: api.companies.getInfo.queryKey(),
      }),
    ]);

  // Resubmit: upload any freshly-picked license files first, then flip the role
  // back to pending so it re-enters the approval queue.
  const resubmit = useMutation({
    mutationFn: async (args: { profileId: string; files: File[] }) => {
      if (args.files.length > 0) {
        await companiesService.uploadProfileLicense(args.profileId, args.files);
      }
      await api.companies.reapplyProfile.call({ profileId: args.profileId });
    },
    onSuccess: refresh,
  });

  if (roles.length === 0) return null;

  return (
    <>
      <Card padding="lg" radius="lg" mt="lg">
      <Group gap="sm" mb="md">
        <Layers size={20} />
        <Title order={3}>Operational Services</Title>
      </Group>
      <Stack gap="sm">
        {roles.map((r) => {
          const status = ROLE_STATUS[r.status] ?? {
            color: "gray",
            label: r.status,
          };
          return (
            <Group
              key={r.id}
              justify="space-between"
              align="flex-start"
              wrap="nowrap"
              py="xs"
              style={{
                borderTop: "1px solid var(--mantine-color-edr-border-0)",
              }}
            >
              <Stack gap={4}>
                <Group gap="xs">
                  <Text fw={600}>{ROLE_LABELS[r.type] ?? r.type}</Text>
                  <Badge color={status.color} variant="light" radius="sm">
                    {status.label}
                  </Badge>
                  {r.reference && (
                    <Text size="xs" c="dimmed" ff="monospace">
                      {r.reference}
                    </Text>
                  )}
                </Group>
                {(r.status === "rejected" || r.status === "suspended") &&
                  r.reviewNote && (
                    <Text
                      size="sm"
                      c={r.status === "suspended" ? "orange.7" : "red.7"}
                    >
                      <strong>
                        {r.status === "suspended"
                          ? "Suspension reason:"
                          : "Reviewer note:"}
                      </strong>{" "}
                      {r.reviewNote}
                    </Text>
                  )}

                {r.licenseFiles.length === 0 ? (
                  <Text size="xs" c="edr-muted">
                    No license document
                  </Text>
                ) : (
                  <Stack gap={4}>
                    {r.licenseFiles.map((f) => (
                      <Group key={f.id} gap="xs" wrap="nowrap">
                        <FileText
                          size={14}
                          className="text-edr-muted"
                          style={{ flexShrink: 0 }}
                        />
                        <Anchor
                          component="button"
                          type="button"
                          size="xs"
                          lineClamp={1}
                          onClick={() =>
                            void fetchViewableFile(f.id, f.name).then(view)
                          }
                        >
                          {f.name}
                        </Anchor>
                        {f.status !== "live" && (
                          <Badge
                            size="xs"
                            radius="sm"
                            variant="light"
                            color={
                              f.status === "pending_remove" ? "red" : "yellow"
                            }
                          >
                            {f.status === "pending_remove"
                              ? "Removal pending"
                              : "Pending"}
                          </Badge>
                        )}
                      </Group>
                    ))}
                  </Stack>
                )}
              </Stack>

              {r.status === "rejected" && (
                <ResubmitService
                  pending={resubmit.isPending}
                  onResubmit={(files) =>
                    resubmit.mutate({ profileId: r.id, files })
                  }
                />
              )}
            </Group>
          );
        })}
      </Stack>
      </Card>
      {viewer}
    </>
  );
}

/** Rejected-role actions: optionally replace the license, then resubmit. */
function ResubmitService({
  pending,
  onResubmit,
}: {
  pending: boolean;
  onResubmit: (files: File[]) => void;
}) {
  const [files, setFiles] = useState<File[]>([]);

  return (
    <Group gap="xs" wrap="nowrap">
      <FileButton onChange={setFiles} accept="application/pdf,image/*" multiple>
        {(props) => (
          <Button
            {...props}
            size="xs"
            variant="light"
            leftSection={<UploadCloud size={14} />}
          >
            {files.length > 0 ? `${files.length} file(s)` : "Replace license"}
          </Button>
        )}
      </FileButton>
      <Button
        size="xs"
        color="edr-green"
        leftSection={<RefreshCw size={14} />}
        loading={pending}
        onClick={() => onResubmit(files)}
      >
        Resubmit
      </Button>
    </Group>
  );
}
