import { useLimits } from '@documenso/ee/server-only/limits/provider/client';
import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation';
import { useSession } from '@documenso/lib/client-only/providers/session';
import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones';
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { formatDocumentsPath, formatTemplatesPath } from '@documenso/lib/utils/teams';
import { trpc } from '@documenso/trpc/react';
import type { TCreateDocumentPayloadSchema } from '@documenso/trpc/server/document-router/create-document.types';
import type { TCreateTemplatePayloadSchema } from '@documenso/trpc/server/template-router/schema';
import { buildDropzoneRejectionDescription } from '@documenso/ui/lib/handle-dropzone-rejection';
import { cn } from '@documenso/ui/lib/utils';
import { DocumentUploadButton as DocumentUploadButtonPrimitive } from '@documenso/ui/primitives/document-upload-button';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro';
import { EnvelopeType } from '@prisma/client';
import { useMemo, useState } from 'react';
import type { FileRejection } from 'react-dropzone';
import { useNavigate, useParams } from 'react-router';
import { match } from 'ts-pattern';

import { useCurrentTeam } from '~/providers/team';

export type DocumentUploadButtonLegacyProps = {
  className?: string;
  type: EnvelopeType;
};

export const DocumentUploadButtonLegacy = ({ className, type }: DocumentUploadButtonLegacyProps) => {
  const { _ } = useLingui();
  const { toast } = useToast();
  const { user } = useSession();
  const { folderId } = useParams();

  const team = useCurrentTeam();

  const navigate = useNavigate();
  const analytics = useAnalytics();
  const organisation = useCurrentOrganisation();

  const userTimezone =
    TIME_ZONES.find((timezone) => timezone === Intl.DateTimeFormat().resolvedOptions().timeZone) ??
    DEFAULT_DOCUMENT_TIME_ZONE;

  const { quota, remaining, refreshLimits } = useLimits();

  const [isLoading, setIsLoading] = useState(false);

  const { mutateAsync: createDocument } = trpc.document.create.useMutation();
  const { mutateAsync: createTemplate } = trpc.template.createTemplate.useMutation();

  const disabledMessage = useMemo(() => {
    if (!user.emailVerified) {
      return msg`Verify your email to upload documents.`;
    }

    // No errors for templates.
    if (type === EnvelopeType.TEMPLATE) {
      return;
    }

    if (organisation.subscription && remaining.documents === 0) {
      return msg`Document upload disabled due to unpaid invoices`;
    }

    if (remaining.documents === 0) {
      return msg`You have reached your document limit.`;
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [remaining.documents, user.emailVerified, team, type]);

  const onFileDrop = async (file: File) => {
    try {
      setIsLoading(true);

      const payload = {
        title: file.name,
        folderId: folderId ?? undefined,
        meta: {
          timezone: userTimezone,
        },
      } satisfies TCreateDocumentPayloadSchema | TCreateTemplatePayloadSchema;

      const formData = new FormData();

      formData.append('payload', JSON.stringify(payload));
      formData.append('file', file);

      // Handle legacy document creation.
      if (type === EnvelopeType.DOCUMENT) {
        const { envelopeId: id } = await createDocument(formData);

        void refreshLimits();

        await navigate(`${formatDocumentsPath(team.url)}/${id}/edit`);

        toast({
          title: _(msg`Document uploaded`),
          description: _(msg`Your document has been uploaded successfully.`),
          duration: 5000,
        });

        analytics.capture('App: Document Uploaded', {
          userId: user.id,
          documentId: id,
          timestamp: new Date().toISOString(),
        });
      }

      // Handle legacy template creation.
      if (type === EnvelopeType.TEMPLATE) {
        const { envelopeId: id } = await createTemplate(formData);

        await navigate(`${formatTemplatesPath(team.url)}/${id}/edit`);

        toast({
          title: _(msg`Template document uploaded`),
          description: _(
            msg`Your document has been uploaded successfully. You will be redirected to the template page.`,
          ),
          duration: 5000,
        });
      }
    } catch (err) {
      const error = AppError.parseError(err);

      console.error(err);

      const errorMessage = match(error.code)
        .with('INVALID_DOCUMENT_FILE', () => msg`You cannot upload encrypted PDFs.`)
        .with(
          AppErrorCode.LIMIT_EXCEEDED,
          () => msg`You have reached your document limit for this month. Please upgrade your plan.`,
        )
        .with(
          'ENVELOPE_ITEM_LIMIT_EXCEEDED',
          () => msg`You have reached the limit of the number of files per envelope.`,
        )
        .with('UNSUPPORTED_FILE_TYPE', () => msg`This file type isn't supported. Please upload a PDF or Word document.`)
        .with(
          'CONVERSION_SERVICE_UNAVAILABLE',
          () => msg`Document conversion is temporarily unavailable. Please try again shortly or upload a PDF.`,
        )
        .with(
          'CONVERSION_FAILED',
          () => msg`We couldn't convert this file. Please check it's a valid Word document or upload a PDF instead.`,
        )
        .otherwise(() => msg`An error occurred while uploading your document.`);

      toast({
        title: _(msg`Error`),
        description: _(errorMessage),
        variant: 'destructive',
        duration: 7500,
      });
    } finally {
      setIsLoading(false);
    }
  };

  const onFileDropRejected = (fileRejections: FileRejection[]) => {
    toast({
      title: _(msg`Your document failed to upload.`),
      description: _(buildDropzoneRejectionDescription(fileRejections)),
      duration: 5000,
      variant: 'destructive',
    });
  };

  return (
    <div className={cn('relative', className)}>
      <TooltipProvider>
        <Tooltip>
          <TooltipTrigger asChild>
            <div>
              <DocumentUploadButtonPrimitive
                loading={isLoading}
                disabled={disabledMessage !== undefined}
                disabledMessage={disabledMessage}
                onDrop={async (files) => onFileDrop(files[0])}
                onDropRejected={onFileDropRejected}
                type={type}
                internalVersion="1"
              />
            </div>
          </TooltipTrigger>

          {team?.id === undefined &&
            type === EnvelopeType.DOCUMENT &&
            remaining.documents > 0 &&
            Number.isFinite(remaining.documents) && (
              <TooltipContent>
                <p className="text-sm">
                  <Trans>
                    {remaining.documents} of {quota.documents} documents remaining this month.
                  </Trans>
                </p>
              </TooltipContent>
            )}
        </Tooltip>
      </TooltipProvider>
    </div>
  );
};
