import { useCurrentEnvelopeEditor } from '@documenso/lib/client-only/providers/envelope-editor-provider';
import {
  EnvelopeRenderProvider,
  useCurrentEnvelopeRender,
} from '@documenso/lib/client-only/providers/envelope-render-provider';
import { PDF_VIEWER_ERROR_MESSAGES } from '@documenso/lib/constants/pdf-viewer-i18n';
import { ZFieldAndMetaSchema } from '@documenso/lib/types/field-meta';
import { extractFieldInsertionValues } from '@documenso/lib/utils/envelope-signing';
import { toCheckboxCustomText } from '@documenso/lib/utils/fields';
import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
import { AnimateGenericFadeInOut } from '@documenso/ui/components/animate/animate-generic-fade-in-out';
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
import { RecipientSelector } from '@documenso/ui/primitives/recipient-selector';
import { Separator } from '@documenso/ui/primitives/separator';
import type { Faker } from '@faker-js/faker';
import { Trans } from '@lingui/react/macro';
import { FieldType, SigningStatus } from '@prisma/client';
import { FileTextIcon } from 'lucide-react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { match } from 'ts-pattern';

import { EnvelopeGenericPageRenderer } from '~/components/general/envelope-editor/envelope-generic-page-renderer';
import { EnvelopePdfViewer } from '~/components/general/pdf-viewer/envelope-pdf-viewer';

import { EnvelopeEditorInvalidDirectTemplateAlert } from './envelope-editor-invalid-direct-template-alert';
import { EnvelopeRendererFileSelector } from './envelope-file-selector';

export const EnvelopeEditorPreviewPage = () => {
  const { envelope, editorFields, editorConfig } = useCurrentEnvelopeEditor();

  const { currentEnvelopeItem, fields } = useCurrentEnvelopeRender();

  const scrollableContainerRef = useRef<HTMLDivElement>(null);

  const [selectedPreviewMode, setSelectedPreviewMode] = useState<'recipient' | 'signed'>('recipient');

  const [fakerInstance, setFakerInstance] = useState<Faker | null>(null);

  useEffect(() => {
    void import('@faker-js/faker/locale/en').then((mod) => {
      setFakerInstance(mod.faker);
    });
  }, []);

  const fieldsWithPlaceholders = useMemo(() => {
    if (!fakerInstance) {
      return [];
    }

    const faker = fakerInstance;
    return fields.map((field) => {
      const fieldMeta = ZFieldAndMetaSchema.parse(field);

      const recipient = envelope.recipients.find((recipient) => recipient.id === field.recipientId);

      if (!recipient) {
        throw new Error('Recipient not found');
      }

      faker.seed(recipient.id);

      const recipientName = recipient.name || faker.person.fullName();
      const recipientEmail = recipient.email || faker.internet.email();

      faker.seed(recipient.id + field.id);

      return {
        ...field,
        inserted: true,
        ...match(fieldMeta)
          .with({ type: FieldType.TEXT }, ({ fieldMeta }) => {
            let text = fieldMeta?.text || faker.lorem.words(5);

            if (fieldMeta?.characterLimit) {
              text = text.slice(0, fieldMeta?.characterLimit);
            }

            return {
              customText: text,
            };
          })
          .with({ type: FieldType.NUMBER }, ({ fieldMeta }) => {
            let number = fieldMeta?.value ?? '';

            if (number === '') {
              number = faker.number
                .int({
                  min: fieldMeta?.minValue ?? 0,
                  max: fieldMeta?.maxValue ?? 1000,
                })
                .toString();
            }

            return {
              customText: number,
            };
          })
          .with({ type: FieldType.DATE }, () => {
            const date = extractFieldInsertionValues({
              fieldValue: {
                type: FieldType.DATE,
                value: true,
              },
              field,
              documentMeta: envelope.documentMeta,
            });

            return {
              customText: date.customText,
            };
          })
          .with({ type: FieldType.EMAIL }, () => {
            return {
              customText: recipientEmail,
            };
          })
          .with({ type: FieldType.NAME }, () => {
            return {
              customText: recipientName,
            };
          })
          .with({ type: FieldType.INITIALS }, () => {
            return {
              customText: extractInitials(recipientName),
            };
          })
          .with({ type: FieldType.RADIO }, ({ fieldMeta }) => {
            const values = fieldMeta?.values ?? [];

            if (values.length === 0) {
              return '';
            }

            let customText = '';

            const preselectedValue = values.findIndex((value) => value.checked);

            if (preselectedValue !== -1) {
              customText = preselectedValue.toString();
            } else {
              const randomIndex = faker.number.int({ min: 0, max: values.length - 1 });
              customText = randomIndex.toString();
            }

            return {
              customText,
            };
          })
          .with({ type: FieldType.CHECKBOX }, ({ fieldMeta }) => {
            let checkedValues: number[] = [];

            const values = fieldMeta?.values ?? [];

            values.forEach((value, index) => {
              if (value.checked) {
                checkedValues.push(index);
              }
            });

            if (checkedValues.length === 0 && values.length > 0) {
              const numberOfValues = fieldMeta?.validationLength || 1;

              checkedValues = Array.from({ length: numberOfValues }, (_, index) => index);
            }

            return {
              customText: toCheckboxCustomText(checkedValues),
            };
          })
          .with({ type: FieldType.DROPDOWN }, ({ fieldMeta }) => {
            const values = fieldMeta?.values ?? [];

            let customText = fieldMeta?.defaultValue || '';

            if (!customText && values.length > 0) {
              const randomIndex = faker.number.int({ min: 0, max: values.length - 1 });
              customText = values[randomIndex].value;
            }

            return {
              customText,
            };
          })
          .with({ type: FieldType.SIGNATURE }, () => {
            return {
              customText: '',
              signature: {
                signatureImageAsBase64: '',
                typedSignature: recipientName,
              },
            };
          })
          .with({ type: FieldType.FREE_SIGNATURE }, () => {
            return {
              customText: '',
            };
          })
          .exhaustive(),
      };
    });
  }, [fields, envelope, envelope.recipients, envelope.documentMeta, fakerInstance]);

  /**
   * Set the selected recipient to the first recipient in the envelope.
   */
  useEffect(() => {
    editorFields.setSelectedRecipient(envelope.recipients[0]?.id ?? null);
  }, []);

  // Override the parent renderer provider so we can inject custom fields.
  return (
    <EnvelopeRenderProvider
      version="current"
      envelope={envelope}
      envelopeItems={envelope.envelopeItems}
      token={undefined}
      fields={fieldsWithPlaceholders}
      recipients={envelope.recipients.map((recipient) => ({
        ...recipient,
        signingStatus: SigningStatus.SIGNED,
      }))}
      presignToken={editorConfig?.embedded?.presignToken}
      overrideSettings={{
        mode: 'export',
      }}
    >
      <div className="relative flex h-full">
        <div className="flex h-full w-full flex-col overflow-y-auto px-2" ref={scrollableContainerRef}>
          {/* Horizontal envelope item selector */}
          <EnvelopeRendererFileSelector className="px-0" fields={editorFields.localFields} />

          <EnvelopeEditorInvalidDirectTemplateAlert className="mb-4" />

          <Alert variant="warning" className="mx-auto max-w-[800px]">
            <AlertTitle>
              <Trans>Preview Mode</Trans>
            </AlertTitle>
            <AlertDescription>
              <Trans>Preview what the signed document will look like with placeholder data</Trans>
            </AlertDescription>
          </Alert>

          {/* Document View */}
          <div className="mt-4 flex h-full flex-col items-center justify-center">
            {currentEnvelopeItem !== null ? (
              <EnvelopePdfViewer
                customPageRenderer={EnvelopeGenericPageRenderer}
                scrollParentRef={scrollableContainerRef}
                errorMessage={PDF_VIEWER_ERROR_MESSAGES.preview}
              />
            ) : (
              <div className="flex flex-col items-center justify-center py-32">
                <FileTextIcon className="h-10 w-10 text-muted-foreground" />
                <p className="mt-1 text-foreground text-sm">
                  <Trans>No documents found</Trans>
                </p>
                <p className="mt-1 text-muted-foreground text-sm">
                  <Trans>Please upload a document to continue</Trans>
                </p>
              </div>
            )}
          </div>
        </div>

        {/* Right Section - Form Fields Panel */}
        {currentEnvelopeItem && false && (
          <div className="sticky top-0 h-full w-80 flex-shrink-0 overflow-y-auto border-gray-200 border-l bg-white py-4">
            {/* Add fields section. */}
            <section className="px-4">
              {/* <h3 className="mb-2 text-sm font-semibold text-gray-900">
              <Trans>Preivew Mode</Trans>
            </h3> */}

              <Alert variant="neutral">
                <AlertTitle>
                  <Trans>Preview Mode</Trans>
                </AlertTitle>
                <AlertDescription>
                  <Trans>Preview what the signed document will look like with placeholder data</Trans>
                </AlertDescription>
              </Alert>

              {/* <Alert variant="neutral">
              <RadioGroup
                className="gap-y-1"
                value={selectedPreviewMode}
                onValueChange={(value) => setSelectedPreviewMode(value as 'recipient' | 'signed')}
              >
                <div className="flex items-center">
                  <RadioGroupItem
                    id="document-signed-preview"
                    className="pointer-events-none h-3 w-3"
                    value="signed"
                  />
                  <Label
                    htmlFor="document-signed-preview"
                    className="text-foreground ml-1.5 text-xs font-normal"
                  >
                    <Trans>Document Signed Preview</Trans>
                  </Label>
                </div>

                <div className="flex items-center">
                  <RadioGroupItem
                    id="recipient-preview"
                    className="pointer-events-none h-3 w-3"
                    value="recipient"
                  />
                  <Label
                    htmlFor="recipient-preview"
                    className="text-foreground ml-1.5 text-xs font-normal"
                  >
                    <Trans>Recipient Preview</Trans>
                  </Label>
                </div>
              </RadioGroup>
            </Alert>

            <div>Preview what a recipient will see</div>

            <div>Preview the signed document</div> */}
            </section>

            {false && (
              <AnimateGenericFadeInOut key={selectedPreviewMode}>
                {selectedPreviewMode === 'recipient' && (
                  <>
                    <Separator className="my-4" />

                    {/* Recipient selector section. */}
                    <section className="px-4">
                      <h3 className="mb-2 font-semibold text-gray-900 text-sm">
                        <Trans>Selected Recipient</Trans>
                      </h3>

                      <RecipientSelector
                        selectedRecipient={editorFields.selectedRecipient}
                        onSelectedRecipientChange={(recipient) => editorFields.setSelectedRecipient(recipient.id)}
                        recipients={envelope.recipients}
                        className="w-full"
                        align="end"
                      />
                    </section>
                  </>
                )}
              </AnimateGenericFadeInOut>
            )}
          </div>
        )}
      </div>
    </EnvelopeRenderProvider>
  );
};
