import { useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import {
  Anchor,
  Badge,
  Box,
  Button,
  Card,
  Center,
  Group,
  SimpleGrid,
  Stack,
  Text,
  ThemeIcon,
  Tooltip,
} from '@mantine/core';
import {
  IconAnchor,
  IconArrowRight,
  IconBuildingWarehouse,
  IconChevronRight,
  IconFileText,
  IconShieldOff,
  IconShip,
  IconTrendingUp,
} from '@tabler/icons-react';
import {
  useLocalized,
  useGetLicenseCategoriesQuery,
  useGetLicenseTypesQuery,
  useGetMyOperatorTypesQuery,
} from '@ema-platform/api';
import type { LicenseCategory, LicenseType } from '@ema-platform/api';
import { LICENSE_PERMISSIONS, RequirePermission } from '@ema-platform/auth';

/**
 * The licence catalogue an applicant chooses from, grouped by category.
 *
 * Shared by the dashboard and the applications page so the two never drift —
 * they previously listed the same licence types in two different shapes.
 */

const CATEGORY_ICONS: Record<LicenseCategory, typeof IconShip> = {
  CARGO_FREIGHT: IconBuildingWarehouse,
  SHIPPING_AGENCY: IconShip,
  INVESTMENT: IconTrendingUp,
  // The three below are filtered out of this catalogue today
  // (requiresOperatorMode is false for all of them), and are listed only so
  // the record stays total if that ever changes.
  MARITIME_PERSONNEL: IconShip,
  VESSEL_SERVICES: IconAnchor,
  WAIVER_SERVICES: IconShieldOff,
};

function formatFee(amount: string | number | null, currency: string): string {
  if (amount === null || amount === '') return 'No fee';
  const value = Number(amount);
  if (!Number.isFinite(value)) return 'No fee';
  return `${value.toLocaleString('en-US')} ${currency}`;
}

export function LicenseCatalogue() {
  const navigate = useNavigate();
  const localized = useLocalized();
  const { data: types } = useGetLicenseTypesQuery();
  const { data: categories } = useGetLicenseCategoriesQuery();
  const { data: operatorTypes, isLoading: loadingOperatorTypes } =
    useGetMyOperatorTypesQuery();
  // An escape hatch, not a preference: someone who wants to see what else
  // exists can, without first editing their profile to find out.
  const [showAll, setShowAll] = useState(false);

  const declared = useMemo(
    () => new Set((operatorTypes?.items ?? []).map((o) => o.licenseTypeId)),
    [operatorTypes],
  );
  const hasDeclared = declared.size > 0;

  const { groups, orphans } = useMemo(() => {
    const active = (types?.items ?? [])
      .filter((t) => t.isActive)
      // Person-centric registrations (seafarer) are not operator licences:
      // they can never be declared as a mode, have their own entry points,
      // and would only confuse this catalogue — even under "show all".
      .filter((t) => t.requiresOperatorMode !== false)
      // Only what the applicant operates as. The server enforces the same rule
      // on create; this is what stops them starting an application they will
      // be refused at the end of.
      .filter((t) => showAll || !hasDeclared || declared.has(t.id));
    const catalogue = (categories?.items ?? [])
      .slice()
      .sort((a, b) => a.sortOrder - b.sortOrder);

    const known = new Set(catalogue.map((c) => c.key));
    return {
      groups: catalogue
        .map((category) => ({
          category,
          licenseTypes: active.filter((t) => t.category === category.key),
        }))
        .filter((g) => g.licenseTypes.length > 0),
      // A licence type whose category has no catalogue entry would otherwise
      // vanish from the page entirely.
      orphans: active.filter((t) => !known.has(t.category)),
    };
  }, [types, categories, declared, hasDeclared, showAll]);

  // A profile created before modes existed, or one whose modes were all
  // removed. Showing an empty catalogue would read as "there is nothing for
  // you here" when the truth is "tell us what you do".
  if (!loadingOperatorTypes && !hasDeclared && !showAll) {
    return (
      <Card withBorder radius="md" padding="xl">
        <Stack gap="xs" align="center">
          <ThemeIcon variant="light" color="emaPrimary" size="lg" radius="xl">
            <IconBuildingWarehouse size={18} />
          </ThemeIcon>
          <Text size="sm" fw={600}>
            Tell us what you operate as
          </Text>
          <Text size="sm" c="dimmed" ta="center" maw={520}>
            Licences are offered against your mode of operation — freight
            forwarder, shipping agent, multimodal transport operator and so on.
            Choose yours and the licences you can apply for appear here.
          </Text>
          <Group gap="sm" mt="xs">
            <Button size="xs" onClick={() => navigate('/profile#operations')}>
              Set my operations
            </Button>
            <Button size="xs" variant="subtle" onClick={() => setShowAll(true)}>
              Browse all licences
            </Button>
          </Group>
        </Stack>
      </Card>
    );
  }

  if (groups.length === 0 && orphans.length === 0) {
    return (
      <Card withBorder radius="md" padding="xl">
        <Center>
          <Stack gap={6} align="center">
            <ThemeIcon variant="light" color="gray" size="lg" radius="xl">
              <IconFileText size={18} />
            </ThemeIcon>
            <Text size="sm" c="dimmed" ta="center">
              No licence types are available yet. Contact EMA if you were
              expecting one.
            </Text>
          </Stack>
        </Center>
      </Card>
    );
  }

  // In browse-all, a card the applicant cannot yet apply for sends them to the
  // Operations tab rather than into a form the server would refuse to accept.
  const canApply = (type: LicenseType) => !hasDeclared || declared.has(type.id);
  const select = (type: LicenseType) =>
    canApply(type)
      ? navigate(`/licensing/${type.key}/apply`)
      : navigate('/profile#operations');

  return (
    <Stack gap="lg">
      {showAll && hasDeclared && (
        <Group gap="xs">
          <Text size="xs" c="dimmed">
            Showing every licence, including ones outside your operations.
          </Text>
          <Anchor size="xs" onClick={() => setShowAll(false)}>
            Show only mine
          </Anchor>
        </Group>
      )}
      {groups.map(({ category, licenseTypes }) => (
        <CategoryGroup
          key={category.key}
          icon={CATEGORY_ICONS[category.key] ?? IconFileText}
          title={localized(category.name)}
          description={localized(category.description)}
          licenseTypes={licenseTypes}
          canApply={canApply}
          onSelect={select}
        />
      ))}
      {orphans.length > 0 && (
        <CategoryGroup
          icon={IconFileText}
          title="Other licences"
          description="Licence types that have not been assigned a category."
          licenseTypes={orphans}
          canApply={canApply}
          onSelect={select}
        />
      )}
      {hasDeclared && !showAll && (
        <Group gap="xs">
          <Text size="xs" c="dimmed">
            Only licences matching your declared operations are shown.
          </Text>
          <Anchor size="xs" onClick={() => setShowAll(true)}>
            Browse all licences
          </Anchor>
        </Group>
      )}
    </Stack>
  );
}

function CategoryGroup({
  icon: Icon,
  title,
  description,
  licenseTypes,
  canApply,
  onSelect,
}: {
  icon: typeof IconShip;
  title: string;
  description: string;
  licenseTypes: LicenseType[];
  canApply: (type: LicenseType) => boolean;
  onSelect: (type: LicenseType) => void;
}) {
  return (
    <Box>
      <Group gap="xs" mb="xs">
        <ThemeIcon variant="light" color="emaTeal" radius="md" size="md">
          <Icon size={16} />
        </ThemeIcon>
        <Text fw={600} size="sm">
          {title}
        </Text>
        <Text size="xs" c="dimmed">
          {description}
        </Text>
      </Group>
      <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
        {licenseTypes.map((type) => (
          <LicenseTypeCard
            key={type.id}
            type={type}
            canApply={canApply(type)}
            onSelect={onSelect}
          />
        ))}
      </SimpleGrid>
    </Box>
  );
}

function LicenseTypeCard({
  type,
  canApply,
  onSelect,
}: {
  type: LicenseType;
  canApply: boolean;
  onSelect: (type: LicenseType) => void;
}) {
  const localized = useLocalized();
  const capital = type.capitalThreshold ? Number(type.capitalThreshold) : null;

  return (
    <Card
      withBorder
      radius="md"
      padding="md"
      style={{ cursor: 'pointer', height: '100%' }}
      onClick={() => onSelect(type)}
    >
      <Stack gap="xs" justify="space-between" h="100%">
        <Box>
          <Group justify="space-between" align="flex-start" wrap="nowrap">
            <Text fw={600} size="sm" lh={1.35}>
              {localized(type.name)}
            </Text>
            <IconChevronRight
              size={16}
              color="var(--mantine-color-dimmed)"
              style={{ flexShrink: 0, marginTop: 2 }}
            />
          </Group>
          {type.description && (
            <Text size="xs" c="dimmed" mt={6} lineClamp={3}>
              {localized(type.description)}
            </Text>
          )}
        </Box>

        <Box>
          <Group gap={6} mt="sm">
            <Badge size="sm" variant="light" color="emaPrimary">
              {formatFee(type.feeNewApplication, type.feeCurrency)}
            </Badge>
            {capital && (
              <Tooltip label="Minimum capital that must be evidenced by a bank letter">
                <Badge size="sm" variant="light" color="gray">
                  Capital {capital.toLocaleString('en-US')}
                </Badge>
              </Tooltip>
            )}
            {type.issuesCertificate ? (
              <Badge size="sm" variant="light" color="teal">
                {type.validityMonths} months
              </Badge>
            ) : (
              <Tooltip label="Concludes with an EMA decision rather than a certificate">
                <Badge size="sm" variant="light" color="gray">
                  Evaluation only
                </Badge>
              </Tooltip>
            )}
          </Group>
          <RequirePermission anyOf={[LICENSE_PERMISSIONS.CREATE_APPLICATION]} hideOnly>
            <Button
              fullWidth
              mt="sm"
              size="xs"
              variant="light"
              color={canApply ? undefined : 'gray'}
              rightSection={<IconArrowRight size={14} />}
            >
              {canApply ? 'Start application' : 'Add to my operations'}
            </Button>
          </RequirePermission>
        </Box>
      </Stack>
    </Card>
  );
}

export default LicenseCatalogue;
