/**
 * Compose modal — rich text editor (TipTap) with template insert.
 * Used for new mail, reply, and forward.
 * Form validation: React Hook Form + Zod.
 */

import React, { useState, useRef, useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Modal } from '@/components/ui/Modal';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Select } from '@/components/ui/Select';
import { TemplatePicker } from './TemplatePicker';
import { RichTextEditor } from './RichTextEditor';
import type { Mail, MailSignature, SendMailPayload, ReplyPayload, ForwardPayload, MailDraftPayload } from '@/api/mail';
import { uploadAttachment, type UploadedAttachment, replaceSignatureVariables } from '@/api/mail';
import { useAuthStore } from '@/store/authStore';
import { FileText, Paperclip, X } from 'lucide-react';

export type ComposeMode = 'new' | 'reply' | 'forward' | 'draft';

export interface ComposeModalProps {
  open: boolean;
  mode: ComposeMode;
  accountId: string;
  replyToMail: Mail | null;
  forwardMail: Mail | null;
  draftMail?: Mail | null;
  signatures: MailSignature[];
  onSend: (payload: SendMailPayload | ReplyPayload | ForwardPayload, mode: ComposeMode) => Promise<void>;
  onSaveDraft?: (payload: MailDraftPayload) => Promise<void>;
  onClose: () => void;
}

// ── Zod Schema ──

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

function validateEmailList(val: string, ctx: z.RefinementCtx, field: string, required: boolean) {
  const emails = val.split(',').map((s) => s.trim()).filter(Boolean);
  if (required && emails.length === 0) {
    ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'required', path: [field] });
    return;
  }
  for (const email of emails) {
    if (!emailRegex.test(email)) {
      ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'invalidEmail', path: [field] });
      return;
    }
  }
}

const composeSchema = z.object({
  to: z.string().default(''),
  cc: z.string().optional().default(''),
  bcc: z.string().optional().default(''),
  subject: z.string().min(1, 'required'),
  body: z.string().default(''),
}).superRefine((data, ctx) => {
  validateEmailList(data.to, ctx, 'to', true);
  if (data.cc) validateEmailList(data.cc, ctx, 'cc', false);
  if (data.bcc) validateEmailList(data.bcc, ctx, 'bcc', false);
});

type ComposeFormData = z.infer<typeof composeSchema>;

export function ComposeModal({
  open,
  mode,
  accountId,
  replyToMail,
  forwardMail,
  draftMail,
  signatures,
  onSend,
  onSaveDraft,
  onClose,
}: ComposeModalProps) {
  const { t } = useTranslation();
  const authUser = useAuthStore((s) => s.user);
  const authTenant = useAuthStore((s) => s.currentTenant);
  const [showCc, setShowCc] = useState(false);
  const [selectedSignatureId, setSelectedSignatureId] = useState('');
  const [showTemplatePicker, setShowTemplatePicker] = useState(false);
  const [attachments, setAttachments] = useState<UploadedAttachment[]>([]);
  const [uploadingFile, setUploadingFile] = useState(false);
  const [sending, setSending] = useState(false);
  const [savingDraft, setSavingDraft] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const {
    register,
    handleSubmit,
    reset,
    setValue,
    watch,
    formState: { errors },
  } = useForm<ComposeFormData>({
    resolver: zodResolver(composeSchema),
    defaultValues: { to: '', cc: '', bcc: '', subject: '', body: '' },
  });

  const bodyValue = watch('body');

  useEffect(() => {
    if (!open) return;
    if (mode === 'reply' && replyToMail) {
      reset({
        to: replyToMail.from_address,
        cc: '',
        bcc: '',
        subject: replyToMail.subject.startsWith('Re: ') ? replyToMail.subject : `Re: ${replyToMail.subject}`,
        body: `\n\n---\n${replyToMail.body_text.slice(0, 200)}`,
      });
    } else if (mode === 'forward' && forwardMail) {
      reset({
        to: '',
        cc: '',
        bcc: '',
        subject: forwardMail.subject.startsWith('Fwd: ') ? forwardMail.subject : `Fwd: ${forwardMail.subject}`,
        body: `\n\n---\n${t('mail.forwarding')}\n${t('mail.from')}: ${forwardMail.from_address}\n${t('mail.subject')}: ${forwardMail.subject}\n\n${forwardMail.body_text.slice(0, 200)}`,
      });
    } else if (mode === 'draft' && draftMail) {
      reset({
        to: draftMail.to_addresses.join(', '),
        cc: draftMail.cc_addresses.join(', '),
        bcc: draftMail.bcc_addresses.join(', '),
        subject: draftMail.subject,
        body: draftMail.body_html || draftMail.body_text || '',
      });
      setShowCc(draftMail.cc_addresses.length > 0 || draftMail.bcc_addresses.length > 0);
    } else {
      reset({ to: '', cc: '', bcc: '', subject: '', body: '' });
      setAttachments([]);
    }
  }, [open, mode, replyToMail, forwardMail, draftMail, t, reset]);

  const insertSignature = useCallback((signatureId: string) => {
    setSelectedSignatureId(signatureId);
    const sig = signatures.find((s) => s.id === signatureId);
    if (sig) {
      const processedHtml = replaceSignatureVariables(
        sig.body_html,
        { name: authUser ? `${authUser.first_name} ${authUser.last_name}`.trim() : undefined, email: authUser?.email, role: authUser?.role, first_name: authUser?.first_name, last_name: authUser?.last_name },
        { name: authTenant?.name },
      );
      setValue('body', `${bodyValue}<br/><br/>---<br/>${processedHtml}`);
    }
  }, [signatures, authUser, authTenant, setValue, bodyValue]);

  const handleTemplateSelect = useCallback((templateBody: string, templateSubject: string) => {
    setValue('body', templateBody);
    if (templateSubject) {
      setValue('subject', templateSubject);
    }
    setShowTemplatePicker(false);
  }, [setValue]);

  const handleFileSelect = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files || files.length === 0) return;
    setUploadingFile(true);
    try {
      for (let i = 0; i < files.length; i++) {
        const file = files[i];
        if (file.size > 25 * 1024 * 1024) {
          alert(`${file.name} exceeds 25 MB limit`);
          continue;
        }
        const uploaded = await uploadAttachment(file);
        setAttachments((prev) => [...prev, uploaded]);
      }
    } catch (err) {
      console.error('Attachment upload failed:', err);
      alert('Failed to upload attachment');
    } finally {
      setUploadingFile(false);
      if (fileInputRef.current) {
        fileInputRef.current.value = '';
      }
    }
  }, []);

  const handleRemoveAttachment = useCallback((attId: string) => {
    setAttachments((prev) => prev.filter((a) => a.id !== attId));
  }, []);

  const formatBytes = (bytes: number): string => {
    if (bytes < 1024) return `${bytes} B`;
    if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  };

  const parseEmailList = (val: string): string[] =>
    val ? val.split(',').map((s) => s.trim()).filter(Boolean) : [];

  const onSendValidated = useCallback(async (data: ComposeFormData) => {
    setSending(true);
    try {
      const toList = parseEmailList(data.to);
      const ccList = data.cc ? parseEmailList(data.cc) : undefined;
      const bccList = data.bcc ? parseEmailList(data.bcc) : undefined;

      if (mode === 'reply' && replyToMail) {
        const replyPayload: ReplyPayload = {
          account_id: accountId,
          body: data.body,
          is_html: true,
          to: toList,
          cc: ccList,
          signature_id: selectedSignatureId || null,
        };
        await onSend(replyPayload, 'reply');
      } else if (mode === 'forward' && forwardMail) {
        const fwdPayload: ForwardPayload = {
          account_id: accountId,
          to: toList,
          body: data.body,
          is_html: true,
          signature_id: selectedSignatureId || null,
        };
        await onSend(fwdPayload, 'forward');
      } else {
        const sendPayload: SendMailPayload = {
          account_id: accountId,
          to: toList,
          cc: ccList,
          bcc: bccList,
          subject: data.subject,
          body: data.body,
          is_html: true,
          signature_id: selectedSignatureId || null,
          attachments: attachments.map((a) => a.id),
        };
        await onSend(sendPayload, 'new');
      }
      setAttachments([]);
      onClose();
    } finally {
      setSending(false);
    }
  }, [mode, replyToMail, forwardMail, accountId, selectedSignatureId, attachments, onSend, onClose]);

  const handleSaveDraft = useCallback(async () => {
    if (!onSaveDraft) return;
    const data = watch();
    setSavingDraft(true);
    try {
      const toList = parseEmailList(data.to);
      const ccList = data.cc ? parseEmailList(data.cc) : [];
      const bccList = data.bcc ? parseEmailList(data.bcc) : [];
      const payload: MailDraftPayload = {
        account_id: accountId,
        to: toList,
        cc: ccList,
        bcc: bccList,
        subject: data.subject,
        body_text: data.body.replace(/<[^>]*>/g, ''),
        body_html: data.body,
      };
      await onSaveDraft(payload);
    } finally {
      setSavingDraft(false);
    }
  }, [onSaveDraft, watch, accountId]);

  const title = mode === 'reply' ? t('mail.reply') : mode === 'forward' ? t('mail.forward') : mode === 'draft' ? t('mail.editDraft') : t('mail.compose');

  const errorMsg = (key: string | undefined) => {
    if (!key) return undefined;
    if (key === 'required') return t('validation.required');
    if (key === 'invalidEmail') return t('validation.email');
    return key;
  };

  return (
    <Modal open={open} onClose={onClose} title={title} size="xl" closeOnBackdrop={false} fullScreenMobile>
      <form onSubmit={handleSubmit(onSendValidated)} className="space-y-4" data-testid="compose-modal">
        {/* Template picker toggle (formatting toolbar is in RichTextEditor) */}
        <div className="flex items-center gap-2" data-testid="compose-toolbar">
          <button
            onClick={() => setShowTemplatePicker(!showTemplatePicker)}
            className="px-3 py-1.5 rounded hover:bg-secondary-100 text-sm"
            aria-label={t('mail.insertTemplate')}
            title={t('mail.insertTemplate')}
            type="button"
            data-testid="template-picker-toggle"
          >
            {t('mail.template')}
          </button>
        </div>

        {showTemplatePicker && (
          <TemplatePicker onSelect={handleTemplateSelect} />
        )}

        {/* Recipients */}
        <div className="space-y-2">
          <Input
            label={t('mail.to')}
            {...register('to')}
            error={errorMsg(errors.to?.message)}
            placeholder="recipient@example.com"
            required
            data-testid="compose-to"
          />
          <div className="flex items-center gap-2">
            {!showCc ? (
              <button
                onClick={() => setShowCc(true)}
                className="text-sm text-primary-600 hover:text-primary-700"
                type="button"
              >
                {t('mail.showCcBcc')}
              </button>
            ) : (
              <div className="w-full grid grid-cols-1 sm:grid-cols-2 gap-2">
                <Input
                  label={t('mail.cc')}
                  {...register('cc')}
                  error={errorMsg(errors.cc?.message)}
                  placeholder="cc@example.com"
                />
                <Input
                  label={t('mail.bcc')}
                  {...register('bcc')}
                  error={errorMsg(errors.bcc?.message)}
                  placeholder="bcc@example.com"
                />
              </div>
            )}
          </div>
          <Input
            label={t('mail.subject')}
            {...register('subject')}
            error={errorMsg(errors.subject?.message)}
            placeholder={t('mail.subjectPlaceholder')}
            data-testid="compose-subject"
          />
        </div>

        {/* Editor */}
        <div>
          <label className="block text-sm font-medium text-secondary-700 mb-1">{t('mail.body')}</label>
          <RichTextEditor
            content={bodyValue}
            onChange={(html: string) => setValue('body', html)}
            placeholder={t('mail.body')}
          />
        </div>

        {/* Attachments */}
        <div data-testid="compose-attachments">
          <label className="block text-sm font-medium text-secondary-700 mb-1">{t('mail.attachments')}</label>
          <div className="flex items-center gap-2">
            <input
              ref={fileInputRef}
              type="file"
              multiple
              onChange={handleFileSelect}
              className="hidden"
              data-testid="compose-file-input"
            />
            <Button
              variant="secondary"
              size="sm"
              type="button"
              onClick={() => fileInputRef.current?.click()}
              isLoading={uploadingFile}
              icon={
                <Paperclip className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
              }
            >
              {t('mail.addAttachment')}
            </Button>
            <span className="text-xs text-secondary-400">Max 25 MB per file</span>
          </div>
          {attachments.length > 0 && (
            <ul className="mt-2 space-y-1">
              {attachments.map((att) => (
                <li key={att.id} className="flex items-center gap-3 p-2 rounded-md bg-secondary-50">
                  <FileText className="w-5 h-5 text-secondary-400 flex-shrink-0" aria-hidden="true" strokeWidth={2} />
                  <div className="flex-1 min-w-0">
                    <p className="text-sm text-secondary-800 truncate">{att.filename}</p>
                    <p className="text-xs text-secondary-400">{formatBytes(att.size_bytes)}</p>
                  </div>
                  <button
                    type="button"
                    onClick={() => handleRemoveAttachment(att.id)}
                    className="p-1 rounded hover:bg-secondary-200 text-secondary-500"
                    aria-label={t('common.remove')}
                  >
                    <X className="w-4 h-4" aria-hidden="true" strokeWidth={2} />
                  </button>
                </li>
              ))}
            </ul>
          )}
        </div>

        {/* Signature */}
        <Select
          label={t('mail.signature')}
          value={selectedSignatureId}
          onChange={(e) => insertSignature(e.target.value)}
          options={[
            { value: '', label: t('mail.noSignature') },
            ...signatures.map((sig) => ({ value: sig.id, label: sig.name })),
          ]}
        />

        {/* Actions */}
        <div className="flex justify-end gap-2 pt-2 border-t border-secondary-200 sticky bottom-0 bg-white py-3">
          <Button variant="secondary" onClick={onClose} type="button">
            {t('common.cancel')}
          </Button>
          {onSaveDraft && (
            <Button
              variant="secondary"
              onClick={handleSaveDraft}
              isLoading={savingDraft}
              type="button"
              data-testid="compose-save-draft"
            >
              {t('mail.saveDraft')}
            </Button>
          )}
          <Button type="submit" isLoading={sending} data-testid="compose-send">
            {t('mail.send')}
          </Button>
        </div>
      </form>
    </Modal>
  );
}
