'use client';

/**
 * OpenReturnDialog
 *
 * Buyer opens a return request. Flow:
 *  1. On open, mint uploadSessionId via POST /api/returns/draft-uploads
 *  2. Photos uploaded via direct-upload → complete (parentType='pending_return',
 *     parentId=uploadSessionId) — writes supportAttachments rows
 *  3. Submit POST /api/returns with { purchaseId, reason, reasonNote,
 *     uploadSessionId, photoCount }; service adopts attachments by re-parenting
 *     from 'pending_return:uploadSessionId' to 'return:returnId'
 */

import { useEffect, useRef, useState } from 'react';
import { useForm, Controller, useWatch } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
  DialogClose,
} from '@/components/ui/overlays/Dialog';
import { Button } from '@/components/ui/primitives/Button';
import { IconButton } from '@/components/ui/primitives/IconButton';
import { Icon } from '@/components/ui/icons/Icon';
import { Image } from '@/components/ui/primitives/Image';
import {
  Select,
  SelectTrigger,
  SelectContent,
  SelectItem,
  SelectValue,
} from '@/components/ui/primitives/Select';
import { Textarea } from '@/components/ui/primitives/Textarea';
import { FormField } from '@/components/ui/primitives/FormField';
import { useT } from '@/lib/i18n/react';
import { getCsrfToken } from '@/lib/csrf';
import { captureCaught } from '@/lib/observability';

const RETURN_REASONS = [
  'defective',
  'damaged_in_transit',
  'not_as_described',
  'wrong_item_received',
  'changed_mind',
  'wrong_size',
  'arrived_late',
  'other',
] as const;

type ReturnReason = (typeof RETURN_REASONS)[number];

const PHOTO_REQUIRED_REASONS: ReturnReason[] = [
  'defective',
  'damaged_in_transit',
  'not_as_described',
  'wrong_item_received',
];

const BUYER_LIABILITY_REASONS: ReturnReason[] = ['changed_mind', 'wrong_size', 'other'];

const MAX_PHOTOS = 6;

interface UploadedPhoto {
  attachmentId: string;
  thumbUrl: string;
}

const returnSchema = z.object({
  reason: z.enum(RETURN_REASONS),
  reasonNote: z.string().max(1000).optional(),
});

type ReturnFormValues = z.infer<typeof returnSchema>;

export interface OpenReturnDialogProps {
  purchaseId: string;
  onSuccess?: (returnId: string) => void;
  trigger?: React.ReactNode;
}

export function OpenReturnDialog({ purchaseId, onSuccess, trigger }: OpenReturnDialogProps) {
  const t = useT('returns');
  const reasonLabels = t('reason') as unknown as Record<ReturnReason, string>;

  const [open, setOpen] = useState(false);
  const [uploadSessionId, setUploadSessionId] = useState<string | null>(null);
  const [photos, setPhotos] = useState<UploadedPhoto[]>([]);
  const [uploading, setUploading] = useState(false);
  const [photoError, setPhotoError] = useState<string | null>(null);
  const [submitError, setSubmitError] = useState<string | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const {
    handleSubmit,
    control,
    reset,
    formState: { errors, isSubmitting },
  } = useForm<ReturnFormValues>({
    resolver: zodResolver(returnSchema),
    defaultValues: { reason: 'defective', reasonNote: '' },
  });

  const selectedReason = useWatch({ control, name: 'reason' }) ?? 'defective';
  const photoRequired = PHOTO_REQUIRED_REASONS.includes(selectedReason);
  const showBuyerLiabilityNotice = BUYER_LIABILITY_REASONS.includes(selectedReason);

  // Mint upload session on first open
  useEffect(() => {
    if (!open || uploadSessionId) return;
    let cancelled = false;
    (async () => {
      try {
        const res = await fetch('/api/returns/draft-uploads', {
          method: 'POST',
          headers: { 'x-csrf-token': getCsrfToken() },
        });
        const json = (await res.json()) as {
          ok: boolean;
          data?: { uploadSessionId?: string };
          uploadSessionId?: string;
        };
        const sessionId = json.data?.uploadSessionId ?? json.uploadSessionId;
        if (!cancelled && json.ok && sessionId) {
          setUploadSessionId(sessionId);
        }
      } catch (err) {
        captureCaught(err, {
          scope: 'features.returns.OpenReturnDialog.draftUploads',
        });
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [open, uploadSessionId]);

  function handleOpenChange(next: boolean) {
    setOpen(next);
    if (!next) {
      reset();
      setPhotos([]);
      setUploadSessionId(null);
      setPhotoError(null);
      setSubmitError(null);
    }
  }

  async function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (fileInputRef.current) fileInputRef.current.value = '';
    if (!file || !uploadSessionId || photos.length >= MAX_PHOTOS) return;

    setUploading(true);
    setPhotoError(null);
    try {
      const initRes = await fetch('/api/support/attachments/direct-upload', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrf-token': getCsrfToken(),
        },
        body: JSON.stringify({ contentType: file.type, sizeBytes: file.size }),
      });
      const initJson = (await initRes.json()) as {
        ok: boolean;
        uploadToken?: string;
      };
      if (!initJson.ok || !initJson.uploadToken) {
        throw new Error('init_failed');
      }

      const form = new FormData();
      form.append('uploadToken', initJson.uploadToken);
      form.append('parentType', 'pending_return');
      form.append('parentId', uploadSessionId);
      form.append('file', file);

      const completeRes = await fetch('/api/support/attachments/complete', {
        method: 'POST',
        body: form,
        headers: { 'x-csrf-token': getCsrfToken() },
      });
      const completeJson = (await completeRes.json()) as {
        ok: boolean;
        attachmentId?: string;
        variants?: { webp?: string };
        r2Url?: string;
      };
      if (!completeJson.ok || !completeJson.attachmentId) {
        throw new Error('complete_failed');
      }

      const thumbUrl = completeJson.variants?.webp ?? completeJson.r2Url ?? '';
      setPhotos((prev) => [...prev, { attachmentId: completeJson.attachmentId!, thumbUrl }]);
    } catch (err) {
      captureCaught(err, { scope: 'features.returns.OpenReturnDialog.upload' });
      setPhotoError(t('uploadError') as unknown as string);
    } finally {
      setUploading(false);
    }
  }

  function handlePhotoRemove(attachmentId: string) {
    setPhotos((prev) => prev.filter((p) => p.attachmentId !== attachmentId));
  }

  async function onSubmit(values: ReturnFormValues) {
    if (photoRequired && photos.length === 0) {
      setPhotoError(t('photosRequired') as unknown as string);
      return;
    }
    if (!uploadSessionId) {
      setSubmitError(t('submitErrorSession') as unknown as string);
      return;
    }

    setSubmitError(null);

    const res = await fetch('/api/returns', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-csrf-token': getCsrfToken(),
      },
      body: JSON.stringify({
        purchaseId,
        reason: values.reason,
        reasonNote: values.reasonNote || undefined,
        uploadSessionId,
        photoCount: photos.length,
      }),
    });

    if (res.ok) {
      const json = (await res.json()) as {
        data?: { returnId?: string };
        returnId?: string;
      };
      const returnId = json.data?.returnId ?? json.returnId;
      handleOpenChange(false);
      if (returnId) onSuccess?.(returnId);
    } else {
      setSubmitError(t('submitErrorGeneric') as unknown as string);
    }
  }

  return (
    <Dialog open={open} onOpenChange={handleOpenChange}>
      <DialogTrigger asChild>
        {trigger ?? <Button variant="secondary">{t('openButton')}</Button>}
      </DialogTrigger>

      <DialogContent aria-describedby="open-return-desc">
        <DialogHeader>
          <DialogTitle>{t('dialogTitle')}</DialogTitle>
          <DialogDescription id="open-return-desc" className="sr-only">
            {t('dialogTitle')}
          </DialogDescription>
        </DialogHeader>

        <form
          onSubmit={handleSubmit(onSubmit)}
          id="open-return-form"
          className="space-y-4"
          noValidate
        >
          <FormField
            label={t('return_reason_label')}
            htmlFor="return-reason"
            error={errors.reason?.message}
            required
          >
            <Controller
              name="reason"
              control={control}
              render={({ field }) => (
                <Select value={field.value} onValueChange={field.onChange}>
                  <SelectTrigger id="return-reason" aria-invalid={!!errors.reason}>
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    {RETURN_REASONS.map((reason) => (
                      <SelectItem key={reason} value={reason}>
                        {reasonLabels[reason] ?? reason}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              )}
            />
          </FormField>

          {showBuyerLiabilityNotice && (
            <p className="text-text-muted text-xs">
              {t('buyerLiabilityNotice') as unknown as string}
            </p>
          )}

          <FormField label={t('noteLabel')} htmlFor="return-note">
            <Controller
              name="reasonNote"
              control={control}
              render={({ field }) => (
                <Textarea
                  id="return-note"
                  maxLength={1000}
                  rows={3}
                  invalid={!!errors.reasonNote}
                  {...field}
                />
              )}
            />
          </FormField>

          <fieldset>
            <legend className="text-text-primary mb-2 text-sm font-medium">
              {photoRequired
                ? (t('photosLabelRequired') as unknown as string)
                : (t('photosLabel') as unknown as string)}
            </legend>

            {photos.length > 0 && (
              <ul
                className="mb-2 flex flex-wrap gap-2"
                aria-label={t('photosLabel') as unknown as string}
              >
                {photos.map((p) => (
                  <li key={p.attachmentId} className="relative">
                    <Image
                      src={p.thumbUrl}
                      alt=""
                      decorative
                      width={64}
                      height={64}
                      className="border-border-default h-16 w-16 rounded-md border object-cover"
                    />
                    <IconButton
                      aria-label={t('photo_remove')}
                      variant="ghost"
                      size="sm"
                      shape="circle"
                      onClick={() => handlePhotoRemove(p.attachmentId)}
                      className="bg-surface-overlay text-text-primary border-border-default focus-visible:ring-brand-primary-500 absolute -end-1 -top-1 border text-xs"
                    >
                      ×
                    </IconButton>
                  </li>
                ))}
              </ul>
            )}

            {photos.length < MAX_PHOTOS && (
              <div className="flex flex-col gap-2">
                <Button
                  type="button"
                  variant="secondary"
                  size="sm"
                  onClick={() => fileInputRef.current?.click()}
                  disabled={uploading || isSubmitting || !uploadSessionId}
                >
                  <Icon name="Camera" size="sm" aria-hidden />
                  {t('photoUploadLabel')}
                </Button>
                <input
                  ref={fileInputRef}
                  type="file"
                  accept="image/*"
                  aria-label={t('photoUploadLabel') as unknown as string}
                  onChange={handleFileChange}
                  disabled={uploading || isSubmitting || !uploadSessionId}
                  className="sr-only"
                />
                {uploading && (
                  <p className="text-text-secondary mt-1 text-xs">
                    {t('uploading') as unknown as string}
                  </p>
                )}
              </div>
            )}

            {photoError && (
              <p role="alert" className="text-danger-600 mt-1 text-xs">
                {photoError}
              </p>
            )}
          </fieldset>

          {submitError && (
            <p role="alert" className="text-danger-600 text-sm">
              {submitError}
            </p>
          )}
        </form>

        <DialogFooter>
          <DialogClose asChild>
            <Button variant="ghost" type="button" disabled={isSubmitting}>
              {t('dialogCancel')}
            </Button>
          </DialogClose>
          <Button
            type="submit"
            form="open-return-form"
            variant="primary"
            loading={isSubmitting}
            aria-busy={isSubmitting}
            disabled={!uploadSessionId || uploading}
          >
            {t('openButton')}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
