import React, { useEffect, useRef, useState } from 'react';
import { Button, Form } from 'react-bootstrap';
import ReactQuill from 'react-quill-new';
import 'react-quill-new/dist/quill.snow.css';

type Contact = { name: string | null; email: string };
export type Mode = 'new' | 'reply' | 'reply-all' | 'forward';

type Props = {
  show: boolean;
  mode: Mode;
  onClose: () => void;
  onSent: () => void;

  initialTo?: string;
  initialCc?: string;
  initialSubject?: string;
  initialBody?: string;
  quotedHtml?: string | null; // read-only block appended at send time
};

const footerStyles = `
  .gd-compose-quill .ql-container {
    min-height: 140px;
  }
  .gd-compose-quill .ql-editor {
    min-height: 120px;
    padding: 8px 12px;
  }

  /* Footer buttons: solid green, invert on hover */
  .gd-compose-footer-btn {
    min-width: 90px;
    font-weight: 600;
    border-radius: 999px;
    background-color: #00a650;
    border-color: #00a650;
    color: #ffffff;
  }
  .gd-compose-footer-btn:hover,
  .gd-compose-footer-btn:focus {
    background-color: #ffffff;
    color: #00a650;
    border-color: #00a650;
  }
`;

export default function ComposeEmailModal({
  show,
  mode,
  onClose,
  onSent,
  initialTo = '',
  initialCc = '',
  initialSubject = '',
  initialBody = '',
  quotedHtml = '',
}: Props) {
  const overlayRef = useRef<HTMLDivElement | null>(null);

  // main fields
  const [to, setTo] = useState(initialTo);
  const [cc, setCc] = useState(initialCc);
  const [bcc, setBcc] = useState('');
  const [subject, setSubject] = useState(initialSubject);
  const [body, setBody] = useState(initialBody);
  const [format] = useState<'html' | 'text'>('html');

  // contacts (type-ahead)
  const [activeField, setActiveField] = useState<'to' | 'cc' | 'bcc' | null>(null);
  const [results, setResults] = useState<Contact[]>([]);
  const [showList, setShowList] = useState(false);

  // stable debounce timer across renders
  const timerRef = useRef<number | null>(null);

  // when the modal opens / props change, sync initial values
  useEffect(() => {
    if (!show) return;
    setTo(initialTo);
    setCc(initialCc || '');
    setBcc('');
    setSubject(initialSubject || '');
    setBody(initialBody || '');
    setActiveField(null);
    setResults([]);
    setShowList(false);
  }, [show, initialTo, initialCc, initialSubject, initialBody]);

  /* ------------------- contacts search (with robust mapping) ------------------- */

  const parseLabel = (str: string): { name: string | null; email: string | null } => {
    const trimmed = str.trim();
    const emailMatch = trimmed.match(/([^\s<]+@[^\s>]+)/);
    const email = emailMatch ? emailMatch[1] : null;

    if (!email) {
      return { name: null, email: null };
    }

    // try to grab name from "Name <email>"
    const before = trimmed.split(email)[0].replace(/[<>"']/g, '').trim();
    const name = before || null;
    return { name, email };
  };

  const normalizeContactObject = (c: any): Contact | null => {
    if (!c || typeof c !== 'object') return null;

    // Preferred explicit fields
    const nameField =
      c.name ??
      c.full_name ??
      c.fullName ??
      c.contact_name ??
      c.display_name ??
      c.label ??
      c.text ??
      null;

    const emailField =
      c.email ??
      c.contact_email ??
      c.primary_email ??
      c.value ??
      c.email_address ??
      c.address ??
      c.mail ??
      null;

    let name: string | null = nameField ? String(nameField) : null;
    let email: string | null = emailField ? String(emailField) : null;

    // If explicit email is missing, scan all string fields for something with '@'
    if (!email) {
      for (const key of Object.keys(c)) {
        const v = c[key];
        if (typeof v === 'string' && v.includes('@')) {
          email = v.trim();
          break;
        }
      }
    }

    // If we still don't have email, but have a label/text, try parsing "Name <email>"
    if (!email && typeof name === 'string') {
      const parsed = parseLabel(name);
      if (parsed.email) {
        email = parsed.email;
        if (parsed.name) {
          name = parsed.name;
        }
      }
    }

    // If we only have a string somewhere like "Alex <alex@..>" in text/label
    if (!email && typeof c.text === 'string') {
      const parsed = parseLabel(c.text);
      if (parsed.email) {
        email = parsed.email;
        name = parsed.name;
      }
    }

    if (!email) return null;

    return {
      name: name ? String(name) : null,
      email: String(email),
    };
  };

  const normalizeContacts = (raw: any): Contact[] => {
    let arr: any[] = [];

    if (Array.isArray(raw)) {
      arr = raw;
    } else if (raw && typeof raw === 'object') {
      // support {data: [...]}, {results: [...]}, {contacts: [...]}
      const maybe =
        (raw as any).data ||
        (raw as any).results ||
        (raw as any).contacts ||
        null;
      if (Array.isArray(maybe)) arr = maybe;
    }

    return arr
      .map((c) => normalizeContactObject(c))
      .filter((c): c is Contact => !!c);
  };

  const search = (q: string) => {
    // clear previous timer
    if (timerRef.current !== null) {
      window.clearTimeout(timerRef.current);
    }

    const term = (q || '').trim();
    if (!term || term.length < 2) {
      setResults([]);
      setShowList(false);
      return;
    }

    timerRef.current = window.setTimeout(async () => {
      try {
        const endpoints = ['/email/contacts', '/api/email/contacts'];
        let lastErr: any = null;
        let allContacts: Contact[] = [];

        for (const base of endpoints) {
          try {
            const url = `${base}?q=${encodeURIComponent(term)}`;
            const r = await fetch(url, {
              credentials: 'same-origin',
              headers: {
                'X-Requested-With': 'XMLHttpRequest',
                Accept: 'application/json',
              },
            });
            if (!r.ok) {
              lastErr = new Error(`contacts ${r.status}`);
              continue;
            }
            const raw = await r.json();
            console.log('[compose] contacts raw from', base, raw);
            const contacts = normalizeContacts(raw);
            if (contacts.length) {
              allContacts = contacts;
              break; // prefer first endpoint that returns data
            }
          } catch (e) {
            lastErr = e;
          }
        }

        console.log('[compose] contacts normalized:', allContacts);

        setResults(allContacts);
        setShowList(allContacts.length > 0);

        if (!allContacts.length && lastErr) {
          console.warn('[compose] contacts search had no results', lastErr);
        }
      } catch (e) {
        console.error('[compose] contacts search error', e);
        setResults([]);
        setShowList(false);
      }
    }, 160) as unknown as number;
  };

  const insertLabel = (field: 'to' | 'cc' | 'bcc', label: string) => {
    const apply = (current: string, replaceAll = false) => {
      const cur = (current || '').trim();
      if (replaceAll) return `${label};`;

      const parts = cur
        .split(';')
        .map((p) => p.trim())
        .filter(Boolean);
      const last = parts[parts.length - 1] || '';
      const isEmail = /^[^@\s;,:<>"]+@[^@\s;,:<>"]+\.[A-Za-z0-9-]{2,}$/.test(last);
      if (!isEmail) parts.pop(); // drop stub
      parts.push(label);
      return parts.join('; ') + ';';
    };

    if (field === 'to' && mode === 'reply') {
      setTo((c) => apply(c, true));
    } else if (field === 'to') {
      setTo((c) => apply(c));
    } else if (field === 'cc') {
      setCc((c) => apply(c));
    } else {
      setBcc((c) => apply(c));
    }

    setShowList(false);
    setActiveField(null);
  };

  const send = async () => {
    const csrf =
      (
        document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement | null
      )?.content || '';

    const fd = new FormData();
    fd.append('_token', csrf);
    fd.append('to', to || '');
    fd.append('cc', cc || '');
    fd.append('bcc', bcc || '');
    fd.append('subject', subject || '');
    fd.append('body', (body || '') + (quotedHtml || ''));
    fd.append('format', format);

    const endpoints = ['/email/send', '/api/email/send'];

    try {
      let lastError: any = null;

      for (const url of endpoints) {
        try {
          const r = await fetch(url, {
            method: 'POST',
            credentials: 'same-origin',
            headers: { 'X-Requested-With': 'XMLHttpRequest' },
            body: fd,
          });

          if (!r.ok) {
            if (r.status === 404) {
              lastError = new Error(`Send failed (${r.status})`);
              continue;
            }
            throw new Error(`Send failed (${r.status})`);
          }

          onClose();
          onSent();
          return;
        } catch (e) {
          lastError = e;
        }
      }

      throw lastError || new Error('Send failed');
    } catch (e: any) {
      alert(e?.message || 'Send failed');
    }
  };

  if (!show) return null;

  const title =
    mode === 'new' ? 'New email' : mode === 'forward' ? 'Forward' : 'Reply';

  return (
    <div
      ref={overlayRef}
      className="position-fixed top-0 start-0 w-100 h-100 d-flex align-items-center justify-content-center"
      style={{ background: 'rgba(0,0,0,0.35)', zIndex: 2000 }}
      // only close when the *backdrop* itself is clicked
      onMouseDown={(e) => {
        if (e.target === overlayRef.current) {
          onClose();
        }
      }}
    >
      <div
        className="bg-white rounded-3 shadow-lg"
        style={{
          width: 'min(1100px, 96vw)',
          maxHeight: '92vh',
          display: 'flex',
          flexDirection: 'column',
          border: '3px solid #013254',
        }}
      >
        {/* Header: dark blue bar like page headers */}
        <div
          className="d-flex justify-content-between align-items-center px-4 py-3 border-bottom"
          style={{ backgroundColor: '#013254', color: '#fff' }}
        >
          <h5 className="mb-0 fw-semibold">{title}</h5>
          <button
            type="button"
            className="btn-close btn-close-white"
            aria-label="Close"
            onClick={onClose}
          />
        </div>

        {/* Small CSS tweak to tighten the editor height + footer buttons */}
        <style>{footerStyles}</style>

        {/* Body */}
        <div className="px-4 py-3" style={{ flex: 1, overflowY: 'auto' }}>
          {/* TO */}
          <div className="mb-2 position-relative">
            <Form.Control
              placeholder="To"
              value={to}
              onFocus={() => {
                setActiveField('to');
                search(to);
              }}
              onChange={(e) => {
                setTo(e.target.value);
                setActiveField('to');
                search(e.target.value);
              }}
            />
            {activeField === 'to' && showList && results.length > 0 && (
              <div
                className="position-absolute bg-white border rounded shadow-sm w-100"
                style={{ zIndex: 3000, maxHeight: 220, overflowY: 'auto' }}
              >
                {results.map((c, i) => {
                  const label = c.name ? `${c.name} <${c.email}>` : c.email;
                  return (
                    <div
                      key={`${c.email}-${i}`}
                      className="p-2"
                      style={{ cursor: 'pointer' }}
                      onMouseDown={() => insertLabel('to', label)}
                    >
                      <strong>{c.name || c.email}</strong>
                      {c.name ? (
                        <span className="text-muted ms-2">{c.email}</span>
                      ) : null}
                    </div>
                  );
                })}
              </div>
            )}
          </div>

          {/* CC / BCC */}
          <div className="mb-2 d-flex gap-2">
            <div className="flex-fill position-relative">
              <Form.Control
                placeholder="Cc"
                value={cc}
                onFocus={() => {
                  setActiveField('cc');
                  search(cc);
                }}
                onChange={(e) => {
                  setCc(e.target.value);
                  setActiveField('cc');
                  search(e.target.value);
                }}
              />
              {activeField === 'cc' && showList && results.length > 0 && (
                <div
                  className="position-absolute bg-white border rounded shadow-sm w-100"
                  style={{ zIndex: 3000, maxHeight: 220, overflowY: 'auto' }}
                >
                  {results.map((c, i) => {
                    const label = c.name ? `${c.name} <${c.email}>` : c.email;
                    return (
                      <div
                        key={`${c.email}-${i}`}
                        className="p-2"
                        style={{ cursor: 'pointer' }}
                        onMouseDown={() => insertLabel('cc', label)}
                      >
                        <strong>{c.name || c.email}</strong>
                        {c.name ? (
                          <span className="text-muted ms-2">{c.email}</span>
                        ) : null}
                      </div>
                    );
                  })}
                </div>
              )}
            </div>

            <div className="flex-fill position-relative">
              <Form.Control
                placeholder="Bcc"
                value={bcc}
                onFocus={() => {
                  setActiveField('bcc');
                  search(bcc);
                }}
                onChange={(e) => {
                  setBcc(e.target.value);
                  setActiveField('bcc');
                  search(e.target.value);
                }}
              />
              {activeField === 'bcc' && showList && results.length > 0 && (
                <div
                  className="position-absolute bg-white border rounded shadow-sm w-100"
                  style={{ zIndex: 3000, maxHeight: 220, overflowY: 'auto' }}
                >
                  {results.map((c, i) => {
                    const label = c.name ? `${c.name} <${c.email}>` : c.email;
                    return (
                      <div
                        key={`${c.email}-${i}`}
                        className="p-2"
                        style={{ cursor: 'pointer' }}
                        onMouseDown={() => insertLabel('bcc', label)}
                      >
                        <strong>{c.name || c.email}</strong>
                        {c.name ? (
                          <span className="text-muted ms-2">{c.email}</span>
                        ) : null}
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          </div>

          {/* Subject */}
          <div className="mb-3">
            <Form.Control
              placeholder="Subject"
              value={subject}
              onChange={(e) => setSubject(e.target.value)}
            />
          </div>

          {/* Quill editor – smaller height */}
          <div className="gd-compose-quill">
            <ReactQuill
              theme="snow"
              value={body}
              onChange={(html) => setBody(html)}
            />
          </div>

          {/* Read-only quoted original */}
          {quotedHtml ? (
            <div
              className="mt-2 p-2 border rounded bg-light"
              style={{ maxHeight: 260, overflowY: 'auto' }}
            >
              <div dangerouslySetInnerHTML={{ __html: quotedHtml }} />
            </div>
          ) : null}
        </div>

        {/* Footer */}
        <div className="px-4 py-3 border-top d-flex justify-content-end gap-2">
          <Button className="gd-compose-footer-btn" onClick={onClose}>
            Cancel
          </Button>
          <Button className="gd-compose-footer-btn" onClick={send}>
            Send
          </Button>
        </div>
      </div>
    </div>
  );
}
