import {
  useCallback,
  useState,
  type ComponentProps,
  type Dispatch,
  type ReactElement,
  type SetStateAction,
} from 'react';
import { CircleX } from 'lucide-react';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip.js';
import { DocumentType } from '../../../gql/graphql.js';
import { useCloseDocument } from '../../../hooks/use-close-document.js';
import { Button } from '../../ui/button.js';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog.js';
import { ConfirmationModal, PreviewDocumentModal } from '../index.js';

type Props = ComponentProps<typeof Button> & {
  documentId: string;
  couldIssueCreditInvoice: boolean;
  /** Called after the document was closed (or a credit invoice issued for it). */
  onChange?: () => void;
  /**
   * Drive the dialog from the outside. When `setOpen` is passed the component renders no trigger
   * button of its own, so hosts that already have a trigger — a dropdown menu item, for instance —
   * can open it without nesting a button inside their own control.
   */
  open?: boolean;
  setOpen?: Dispatch<SetStateAction<boolean>>;
};

export function CloseDocumentButton({
  documentId,
  couldIssueCreditInvoice,
  onChange,
  open: externalOpen,
  setOpen: setExternalOpen,
  ...props
}: Props): ReactElement {
  const { closeDocument } = useCloseDocument();
  const [localOpen, setLocalOpen] = useState(false);
  const [previewCreditInvoice, setPreviewCreditInvoice] = useState(false);

  // `open` and `setOpen` are a pair: with only one of them the dialog would read the external value
  // but write to local state (or vice versa) and get stuck, so fall back to local state unless both
  // are supplied.
  const isControlled = setExternalOpen !== undefined && externalOpen !== undefined;
  const open = isControlled ? externalOpen : localOpen;
  const setOpen = isControlled ? setExternalOpen : setLocalOpen;

  const onFinallyClose = useCallback(async () => {
    const closed = await closeDocument({ documentId });
    // The hook resolves `false` on failure — don't report a change that never happened.
    if (closed) {
      onChange?.();
    }
  }, [closeDocument, documentId, onChange]);

  if (!couldIssueCreditInvoice) {
    return (
      <ConfirmationModal
        onConfirm={onFinallyClose}
        title="Are you sure you want to close this document?"
        open={isControlled ? open : undefined}
        setOpen={isControlled ? setOpen : undefined}
      >
        {isControlled ? undefined : (
          <Button className="size-7.5 text-red-600" variant="ghost" {...props}>
            <Tooltip>
              <TooltipTrigger>
                <CircleX className="size-5" />
              </TooltipTrigger>
              <TooltipContent>
                <p>Close Document</p>
              </TooltipContent>
            </Tooltip>
          </Button>
        )}
      </ConfirmationModal>
    );
  }

  return (
    <>
      {!isControlled && (
        <Tooltip>
          <TooltipTrigger>
            <Button
              className="size-7.5 text-red-600"
              variant="ghost"
              {...props}
              onClick={() => setOpen(true)}
            >
              <CircleX className="size-5" />
            </Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>Close Document</p>
          </TooltipContent>
        </Tooltip>
      )}
      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent className="sm:max-w-[425px]">
          <DialogHeader>
            <DialogTitle>Should Issue Credit Invoice?</DialogTitle>
          </DialogHeader>

          <DialogFooter>
            <Button
              onClick={() => {
                setOpen(false);
                onFinallyClose();
              }}
              variant="secondary"
            >
              Just Close
            </Button>
            <Button
              onClick={() => {
                setOpen(false);
                setPreviewCreditInvoice(true);
              }}
              variant="default"
            >
              Issue Credit Invoice
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
      <PreviewDocumentModal
        documentId={documentId}
        documentType={DocumentType.CreditInvoice}
        open={previewCreditInvoice}
        setOpen={setPreviewCreditInvoice}
        onIssued={onChange}
      />
    </>
  );
}
