import { useEffect, useState } from 'react';
import {
  Alert,
  Button,
  Container,
  Group,
  Paper,
  Stack,
  Tabs,
  Text,
  TextInput,
} from '@mantine/core';
import {
  IconAlertCircle,
  IconCode,
  IconLayoutBoard,
  IconLock,
  IconPlus,
} from '@tabler/icons-react';
import { useTranslation } from 'react-i18next';
import {
  extractErrorMessage,
  useArchiveLicenseTemplateMutation,
  useCreateLicenseTemplateMutation,
  useDeleteLicenseTemplateMutation,
  useGetBuiltInTemplateQuery,
  useGetLicenseTemplatesQuery,
  useGetLicenseTypesQuery,
  useGetRanksQuery,
  useGetTemplateVariablesQuery,
  usePublishLicenseTemplateMutation,
  useUpdateLicenseValidityMutation,
  useUpdateLicenseTemplateMutation,
} from '@ema-platform/api';
import { EmptyState, ErrorState, PageHeader, PdfPreviewModal } from '@ema-platform/ui';
import { usePermissions, LICENSE_PERMISSIONS as PERMISSIONS } from '@ema-platform/auth';
import { BlockPropertiesPanel } from '../components/BlockPropertiesPanel';
import { DesignerToolbar } from '../components/DesignerToolbar';
import { NewVersionModal } from '../components/NewVersionModal';
import { TemplateActionBar } from '../components/TemplateActionBar';
import { TemplateBackgroundPanel } from '../components/TemplateBackgroundPanel';
import { TemplateCanvas } from '../components/TemplateCanvas';
import { TemplateEditor } from '../components/TemplateEditor';
import { TemplateVariableList } from '../components/TemplateVariableList';
import { TemplateVersionList } from '../components/TemplateVersionList';
import { pageOptionsFor } from '../config/designer';
import { compileLayoutToHbs } from '../config/layout-compiler';
import { useDesignerActions } from '../hooks/useDesignerActions';
import { useTemplateDraft } from '../hooks/useTemplateDraft';
import { useTemplatePreview } from '../hooks/useTemplatePreview';

/**
 * Where the authority designs the certificate its licensees receive.
 *
 * The layout used to be a Handlebars file inside the deployed image, so any
 * change to the authority's own certificate needed a developer and a release.
 * Here it is data: staff author a version, preview the real PDF, and publish.
 * Publishing archives the incumbent, so exactly one design is live per licence
 * type and previously issued certificates keep the design they were made from.
 */
export function CertificateDesignerPage() {
  const { t } = useTranslation();
  const { can } = usePermissions();

  const canEdit = can([PERMISSIONS.UPDATE_TEMPLATE]);
  const canPublish = can([PERMISSIONS.PUBLISH_TEMPLATE]);

  const { data: licenseTypes } = useGetLicenseTypesQuery();
  const [typeId, setTypeId] = useState<string | null>(null);
  const [rankId, setRankId] = useState<string | null>(null);

  const {
    data: allTemplates = [],
    isLoading,
    isError,
    error,
    refetch,
  } = useGetLicenseTemplatesQuery(typeId ?? undefined, { skip: !typeId });
  // The list is per licence type; a rank-specific design and the type's
  // default both come back, so the version list is scoped to whichever the
  // toolbar has selected.
  const templates = allTemplates.filter((tpl) => (tpl.rankId ?? null) === rankId);
  const { data: variables = [] } = useGetTemplateVariablesQuery();
  const { data: builtIn } = useGetBuiltInTemplateQuery();

  const [createTemplate, { isLoading: creating }] = useCreateLicenseTemplateMutation();
  const [updateTemplate, { isLoading: saving }] = useUpdateLicenseTemplateMutation();
  const [publishTemplate, { isLoading: publishing }] = usePublishLicenseTemplateMutation();
  const [archiveTemplate] = useArchiveLicenseTemplateMutation();
  const [deleteTemplate] = useDeleteLicenseTemplateMutation();
  const [updateValidity, { isLoading: savingValidity }] = useUpdateLicenseValidityMutation();

  const draft = useTemplateDraft(templates);
  const run = useDesignerActions();
  const { previewUrl, open: openPreview, close: closePreview } = useTemplatePreview();

  const [newOpen, setNewOpen] = useState(false);
  const [newName, setNewName] = useState('');
  const [validityMonths, setValidityMonths] = useState<number>(12);
  const [mode, setMode] = useState<'canvas' | 'source'>('canvas');

  const selectedType = licenseTypes?.items?.find((type) => type.id === typeId);

  // A rank ladder only exists for CoC/CoP — every other licence type designs
  // one certificate for everyone who holds it. Keyed on `key`, not
  // `certificateCategory`: that STCW-mapping column is unset on the seeded
  // CoC/CoP rows (it's authored later, per StcwMappingPanel), while `key` is
  // the stable identity CertificateEligibilityService itself branches on.
  // CoC/CoP are each a single LicenseType spanning every department's ladder
  // (the applicant's own department, not the type, decides which ladder they
  // climb), so the picker offers every rank in the ladder across all
  // departments rather than one department's.
  const rankCategory: 'COC' | 'COP' | null =
    selectedType?.key === 'CERTIFICATE_OF_COMPETENCY'
      ? 'COC'
      : selectedType?.key === 'CERTIFICATE_OF_PROFICIENCY'
        ? 'COP'
        : null;
  const isRankScoped = rankCategory !== null;
  const { data: allRanks } = useGetRanksQuery(undefined, { skip: !isRankScoped });
  const ranks = (allRanks?.items ?? [])
    .filter((r) => r.certificateCategory === rankCategory)
    .sort((a, b) => a.sortOrder - b.sortOrder);

  // Default to the first licence type so the page is never an empty shell.
  useEffect(() => {
    if (!typeId && licenseTypes?.items?.length) setTypeId(licenseTypes.items[0].id);
  }, [licenseTypes, typeId]);

  useEffect(() => {
    if (selectedType) setValidityMonths(selectedType.validityMonths ?? 12);
  }, [selectedType]);

  // Switching licence type leaves a stale rank selected from the previous
  // type's ladder — reset to the type's default design.
  useEffect(() => {
    setRankId(null);
  }, [typeId]);

  function startNewVersion() {
    setNewName(
      `${selectedType?.name?.en ?? 'Certificate'} v${(templates[0]?.version ?? 0) + 1}`,
    );
    setNewOpen(true);
  }

  const editingLocked = !canEdit || draft.isPublished;

  return (
    <Container size="xl" py="md">
      <PageHeader
        title={t('designer.title', 'Certificate designer')}
        subtitle={t(
          'designer.subtitle',
          'Design the certificate issued to licence holders, and set how long it stays valid.',
        )}
      />

      <DesignerToolbar
        licenseTypes={licenseTypes?.items ?? []}
        typeId={typeId}
        onTypeChange={(value) => {
          setTypeId(value);
          draft.setSelectedId(null);
        }}
        ranks={ranks}
        rankId={rankId}
        onRankChange={(value) => {
          setRankId(value);
          draft.setSelectedId(null);
        }}
        validityMonths={validityMonths}
        onValidityChange={setValidityMonths}
        currentValidityMonths={selectedType?.validityMonths}
        canEdit={canEdit}
        savingValidity={savingValidity}
        onSaveValidity={() =>
          run(
            () => updateValidity({ id: typeId as string, validityMonths }).unwrap(),
            t('designer.validitySaved', 'Validity updated'),
          )
        }
        onNewVersion={startNewVersion}
      />

      {isError ? (
        <ErrorState
          title={t('designer.loadFailed', 'Could not load the designs')}
          description={extractErrorMessage(error)}
          onRetry={() => refetch()}
          icon={IconAlertCircle}
        />
      ) : !isLoading && templates.length === 0 ? (
        <EmptyState
          title={t('designer.empty', 'No design yet for this licence type')}
          description={t(
            'designer.emptyBody',
            'Certificates currently use the built-in layout. Create a version to take control of it.',
          )}
          action={
            canEdit
              ? { label: t('designer.newVersion', 'New version'), onClick: startNewVersion }
              : undefined
          }
        />
      ) : (
        <Group align="flex-start" gap="md" wrap="nowrap">
          <TemplateVersionList
            templates={templates}
            selectedId={draft.selectedId}
            onSelect={draft.setSelectedId}
          />

          <Stack gap="sm" style={{ flex: 1, minWidth: 0 }}>
            <TemplateBackgroundPanel
              backgroundUrl={draft.backgroundUrl}
              onBackgroundChange={draft.setBackgroundUrl}
              logoUrl={draft.logoUrl}
              onLogoChange={draft.setLogoUrl}
              logoPlacement={draft.logoPlacement}
              onLogoPlacementChange={draft.setLogoPlacement}
              landscape={draft.landscape}
              onLandscapeChange={draft.setLandscape}
              disabled={editingLocked}
            />

            {/* A published design is immutable by rule -- certificates were
                issued from it -- so the editor is locked. Without this the
                screen looks broken rather than deliberately read-only, which
                is what "edit is not available" turns out to mean. */}
            {draft.isPublished && (
              <Alert
                variant="light"
                color="blue"
                icon={<IconLock size={18} />}
                title={t('designer.liveDesign', 'This is the live design')}
              >
                <Stack gap="xs" align="flex-start">
                  <Text size="sm">
                    {t(
                      'designer.liveDesignBody',
                      'Certificates have been issued from this version, so it cannot be changed. Create a new version to edit — it starts as a copy of this one, and only replaces it when you publish.',
                    )}
                  </Text>
                  {canEdit && (
                    <Button
                      size="xs"
                      leftSection={<IconPlus size={14} />}
                      onClick={startNewVersion}
                    >
                      {t('designer.newVersionFromThis', 'New version from this design')}
                    </Button>
                  )}
                </Stack>
              </Alert>
            )}

            <Tabs value={mode} onChange={(value) => setMode(value as 'canvas' | 'source')}>
              <Tabs.List>
                <Tabs.Tab value="canvas" leftSection={<IconLayoutBoard size={15} />}>
                  {t('designer.tabCanvas', 'Visual editor')}
                </Tabs.Tab>
                <Tabs.Tab value="source" leftSection={<IconCode size={15} />}>
                  {t('designer.tabSource', 'HTML source')}
                </Tabs.Tab>
              </Tabs.List>

              <Tabs.Panel value="canvas" pt="sm">
                <Stack gap="sm">
                  <TextInput
                    label={t('designer.name', 'Version name')}
                    value={draft.name}
                    onChange={(e) => draft.setName(e.currentTarget.value)}
                    disabled={editingLocked}
                  />
                  <TemplateCanvas
                    backgroundUrl={draft.backgroundUrl}
                    logoUrl={draft.logoUrl}
                    logoPlacement={draft.logoPlacement}
                    landscape={draft.landscape}
                    placements={draft.placements}
                    selectedId={draft.selectedBlockId}
                    onSelect={draft.setSelectedBlockId}
                    onChange={draft.setPlacements}
                    disabled={editingLocked}
                  />
                  <BlockPropertiesPanel
                    block={draft.selectedBlock}
                    variables={variables}
                    onChange={draft.updateBlock}
                    onDelete={draft.deleteBlock}
                    disabled={editingLocked}
                  />
                </Stack>
              </Tabs.Panel>

              <Tabs.Panel value="source" pt="sm">
                {draft.usesCanvas && (
                  <Paper withBorder p="xs" mb="sm" bg="var(--mantine-color-yellow-light)">
                    <Text size="xs">
                      {t(
                        'designer.canvasOwnsSource',
                        'This design is laid out on the visual editor, which regenerates the HTML on every save. Edits made here will be overwritten — remove all blocks first to hand-write the template.',
                      )}
                    </Text>
                  </Paper>
                )}
                <TemplateEditor
                  name={draft.name}
                  onNameChange={draft.setName}
                  source={draft.source}
                  onSourceChange={draft.setSource}
                  landscape={draft.landscape}
                  onLandscapeChange={draft.setLandscape}
                  editorRef={draft.editorRef}
                  disabled={editingLocked}
                  isPublished={draft.isPublished}
                />
              </Tabs.Panel>
            </Tabs>

            <TemplateActionBar
              // A canvas layout has no Handlebars source until it is saved --
              // the server compiles it -- so gating preview on the source alone
              // left the button dead for exactly the designs the canvas is for.
              hasSource={Boolean(draft.source.trim()) || draft.usesCanvas}
              hasSelection={Boolean(draft.selected)}
              isPublished={draft.isPublished}
              dirty={draft.dirty}
              canEdit={canEdit}
              canPublish={canPublish}
              saving={saving}
              publishing={publishing}
              onPreview={() =>
                openPreview({
                  // A canvas layout is compiled here so the preview shows
                  // unsaved block moves; the server compiles the stored copy.
                  hbsSource: draft.usesCanvas
                    ? compileLayoutToHbs({
                        backgroundUrl: draft.backgroundUrl,
                        logoUrl: draft.logoUrl,
                        logoPlacement: draft.logoPlacement,
                        fieldPlacements: draft.placements,
                      })
                    : draft.source,
                  licenseTypeId: typeId,
                  landscape: draft.landscape,
                })
              }
              onSave={() =>
                run(
                  () =>
                    updateTemplate({
                      id: draft.selected!.id,
                      name: draft.name,
                      // The server recompiles the HTML from the blocks when a
                      // canvas layout is present, so sending the stale source
                      // alongside it would only fight that.
                      hbsSource: draft.usesCanvas ? undefined : draft.source,
                      pageOptions: pageOptionsFor(draft.landscape),
                      backgroundUrl: draft.backgroundUrl || undefined,
                      logoUrl: draft.logoUrl || undefined,
                      logoPlacement: draft.logoPlacement,
                      fieldPlacements: draft.placements,
                    }).unwrap(),
                  t('designer.saved', 'Draft saved'),
                )
              }
              onPublish={() =>
                run(
                  () => publishTemplate(draft.selected!.id).unwrap(),
                  t('designer.published', 'Design published'),
                )
              }
              onArchive={() =>
                run(
                  () => archiveTemplate(draft.selected!.id).unwrap(),
                  t('designer.archived', 'Design withdrawn'),
                )
              }
              onDelete={() =>
                run(
                  () => deleteTemplate(draft.selected!.id).unwrap(),
                  t('designer.deleted', 'Draft deleted'),
                )
              }
            />
          </Stack>

          <TemplateVariableList
            variables={variables}
            disabled={editingLocked}
            canvasMode={mode === 'canvas'}
            onInsert={draft.insertVariable}
            onAddBlock={(key) => draft.addBlock(key)}
            onAddTextBlock={() => draft.addBlock(null, 'Text')}
          />
        </Group>
      )}

      <NewVersionModal
        opened={newOpen}
        name={newName}
        onNameChange={setNewName}
        creating={creating}
        onClose={() => setNewOpen(false)}
        onCreate={() =>
          run(async () => {
            const created = await createTemplate({
              licenseTypeId: typeId as string,
              rankId,
              name: newName.trim(),
              hbsSource: templates.length ? undefined : builtIn?.hbsSource,
            }).unwrap();
            draft.setSelectedId(created.id);
            setNewOpen(false);
          }, t('designer.created', 'Draft created'))
        }
      />

      <PdfPreviewModal
        opened={Boolean(previewUrl)}
        onClose={closePreview}
        url={previewUrl ?? ''}
        title={t('designer.preview', 'Preview')}
      />
    </Container>
  );
}

export default CertificateDesignerPage;
