import { useState, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import Layout from '../../components/Layout';
import LoadingButton from '../../components/LoadingButton';
import { supabase } from '../../lib/supabase';
import { useAuth } from '../../context/AuthContext';
import { generateInvoicePDF } from '../../lib/invoice';
import { blobToEmailAttachment, sendEmail } from '../../lib/email';
import { withTimeout } from '../../lib/withTimeout';

// Computed at module load time — stable for the lifetime of the invoice creation session
const INVOICE_TODAY = new Date().toISOString().split('T')[0];
const INVOICE_NET30 = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];

function newItem(description = '', unit_price = '', quantity = 1, task_id = null, submission_id = null) {
  return { id: crypto.randomUUID(), description, unit_price, quantity, task_id, submission_id };
}

const buildNewItemDescription = (task) => {
  const projectName = task.project?.name || 'No Project';
  const taskTitle = task.title || task.service_type || 'Untitled';
  return `${projectName} • ${taskTitle}`;
};

const buildRevisionItemDescription = (revision) => {
  const projectName = revision.task?.project?.name || 'No Project';
  const taskTitle = revision.task?.title || revision.service_type || 'Revision';
  const versionLabel = 'R' + String(revision.version_number || 0).padStart(2, '0');
  return `${projectName} • ${taskTitle} • Revision ${versionLabel}`;
};

export default function CreateInvoice() {
  const navigate = useNavigate();
  const { currentUser } = useAuth();

  const [companies, setCompanies] = useState([]);
  const [selectedCompanyId, setSelectedCompanyId] = useState('');
  const [uninvoicedTasks, setUninvoicedTasks] = useState([]);
  const [uninvoicedRevisions, setUninvoicedRevisions] = useState([]);
  const [priceList, setPriceList] = useState([]);
  const [billTo, setBillTo] = useState('');
  const [invoiceEmail, setInvoiceEmail] = useState('');
  const [companyRecipients, setCompanyRecipients] = useState([]);
  const [items, setItems] = useState([newItem()]);
  const [notes, setNotes] = useState('');
  const [saving, setSaving] = useState(false);
  const [loadingTasks, setLoadingTasks] = useState(false);
  const dragItem = useRef(null);
  const today = INVOICE_TODAY;
  const net30 = INVOICE_NET30;

  useEffect(() => {
    supabase.from('companies').select('id, name, contact_email').order('name').then(({ data }) => setCompanies(data || []));
  }, []);

  useEffect(() => {
    if (!selectedCompanyId) {
      setUninvoicedTasks([]);
      setUninvoicedRevisions([]);
      setPriceList([]);
      setItems([newItem()]);
      setBillTo('');
      setInvoiceEmail('');
      setCompanyRecipients([]);
      return;
    }
    setBillTo(companies.find(c => c.id === selectedCompanyId)?.name || '');
    setLoadingTasks(true);
    Promise.all([
      supabase.from('projects').select('id').eq('company_id', selectedCompanyId),
      supabase.from('company_prices').select('*').eq('company_id', selectedCompanyId),
      supabase.from('company_members').select('profile:profiles(id, name, email, role, company_id)').eq('company_id', selectedCompanyId),
      supabase.from('profiles').select('id, name, email, role, company_id').eq('company_id', selectedCompanyId).in('role', ['client', 'external']).order('name'),
    ]).then(async ([{ data: projects }, { data: prices }, { data: memberRows }, { data: primaryUsers }]) => {
      setPriceList(prices || []);
      const recipientMap = new Map();
      (memberRows || []).forEach(row => {
        if (row.profile?.email) recipientMap.set(row.profile.id, row.profile);
      });
      (primaryUsers || []).forEach(user => {
        if (user.email) recipientMap.set(user.id, user);
      });
      const recipients = [...recipientMap.values()]
        .sort((a, b) => {
          if (a.role === 'client' && b.role !== 'client') return -1;
          if (a.role !== 'client' && b.role === 'client') return 1;
          return (a.name || '').localeCompare(b.name || '');
        });
      setCompanyRecipients(recipients);
      setInvoiceEmail(recipients[0]?.email || companies.find(c => c.id === selectedCompanyId)?.contact_email || '');
      if (projects && projects.length > 0) {
        const projectIds = projects.map(p => p.id);
        const [{ data: tasks }, { data: revisions }] = await Promise.all([
          supabase
            .from('tasks')
            .select('*, project:projects(name), submissions(service_type, type, version_number)')
            .in('project_id', projectIds)
            .eq('invoiced', false),
          supabase
            .from('submissions')
            .select('*, task:tasks(id, title, project:projects(name), submissions(service_type, type))')
            .eq('type', 'revision')
            .or('revision_type.eq.client_revision,revision_type.is.null')
            .eq('invoiced', false)
            .in('task_id',
              (await supabase.from('tasks').select('id').in('project_id', projectIds)).data?.map(t => t.id) || []
            ),
        ]);
        const tasksWithService = (tasks || []).map(t => {
          const initial = (t.submissions || []).find(s => s.type === 'initial') || (t.submissions || [])[0];
          return { ...t, service_type: initial?.service_type || t.title };
        });
        setUninvoicedTasks(tasksWithService);
        setUninvoicedRevisions(revisions || []);
      } else {
        setUninvoicedTasks([]);
        setUninvoicedRevisions([]);
      }
      setLoadingTasks(false);
    });
  }, [selectedCompanyId, companies]);

  const addTaskAsItem = (task) => {
    const price = priceList.find(p => p.service_type === task.service_type && p.price_type === 'new');
    const description = buildNewItemDescription(task);
    setItems(prev => {
      if (prev.length === 1 && !prev[0].description && !prev[0].unit_price) {
        return [newItem(description, price?.price || '', 1, task.id)];
      }
      return [...prev, newItem(description, price?.price || '', 1, task.id)];
    });
  };

  const getRevisionServiceType = (revision) => {
    const initial = (revision.task?.submissions || []).find(s => s.type === 'initial') || (revision.task?.submissions || [])[0];
    return initial?.service_type || revision.service_type || revision.task?.title || 'Revision';
  };

  const addRevisionAsItem = (revision) => {
    const serviceLabel = getRevisionServiceType(revision);
    const description = buildRevisionItemDescription(revision);
    const price = priceList.find(p => p.service_type === serviceLabel && p.price_type === 'revision');
    setItems(prev => {
      if (prev.length === 1 && !prev[0].description && !prev[0].unit_price) {
        return [newItem(description, price?.price || '', 1, revision.task_id, revision.id)];
      }
      return [...prev, newItem(description, price?.price || '', 1, revision.task_id, revision.id)];
    });
  };

  const updateItem = (id, field, value) => {
    setItems(prev => prev.map(item => item.id === id ? { ...item, [field]: value } : item));
  };

  const removeItem = (id) => setItems(prev => prev.filter(item => item.id !== id));

  const handleDrop = (targetIndex) => {
    if (dragItem.current === null || dragItem.current === targetIndex) { dragItem.current = null; return; }
    setItems(prev => {
      const next = [...prev];
      const [moved] = next.splice(dragItem.current, 1);
      next.splice(targetIndex, 0, moved);
      return next;
    });
    dragItem.current = null;
  };

  const sortItems = (mode) => {
    setItems(prev => {
      const next = [...prev];
      if (mode === 'new-first') return next.sort((a, b) => (!!a.submission_id) - (!!b.submission_id));
      if (mode === 'revision-first') return next.sort((a, b) => (!!b.submission_id) - (!!a.submission_id));
      if (mode === 'az') return next.sort((a, b) => a.description.localeCompare(b.description));
      return next;
    });
  };

  const total = items.reduce((sum, item) => sum + (Number(item.quantity) || 0) * (Number(item.unit_price) || 0), 0);

  const handleSave = async (status) => {
    if (!selectedCompanyId) return alert('Please select a company.');
    if (items.every(i => !i.description)) return alert('Please add at least one line item.');
    if (status === 'sent' && !invoiceEmail.trim()) return alert('Please enter an email recipient before finalizing and sending.');
    if (status === 'sent' && !selectedCompany) return alert('Please select a valid company before finalizing and sending.');
    setSaving(true);
    try {
      const year = new Date().getFullYear();
      const { count, error: countError } = await supabase
        .from('invoices')
        .select('*', { count: 'exact', head: true })
        .gte('created_at', `${year}-01-01`);
      if (countError) throw countError;

      const invoiceNumber = `INV-${year}-${String((count || 0) + 1).padStart(3, '0')}`;
      const initialStatus = status === 'sent' ? 'draft' : status;
      const { data: invoice, error } = await supabase.from('invoices').insert({
        company_id: selectedCompanyId,
        invoice_number: invoiceNumber,
        invoice_date: today,
        due_date: net30,
        status: initialStatus,
        bill_to: billTo || null,
        invoice_email: invoiceEmail.trim() || null,
        notes: notes || null,
        total,
        created_by: currentUser?.id,
      }).select().single();
      if (error || !invoice) throw error || new Error('Invoice record was not created.');

      const validItems = items.filter(i => i.description);
      if (validItems.length > 0) {
        const { error: itemError } = await supabase.from('invoice_items').insert(
          validItems.map(item => ({
            invoice_id: invoice.id,
            task_id: item.task_id || null,
            submission_id: item.submission_id || null,
            description: item.description,
            quantity: Number(item.quantity) || 1,
            unit_price: Number(item.unit_price) || 0,
          }))
        );
        if (itemError) throw itemError;
      }

      const taskIds = [...new Set(validItems.filter(i => i.task_id && !i.submission_id).map(i => i.task_id))];
      if (taskIds.length > 0) {
        const { error: taskError } = await supabase.from('tasks').update({ invoiced: true, status: 'invoiced' }).in('id', taskIds);
        if (taskError) throw taskError;
      }

      const submissionIds = [...new Set(validItems.filter(i => i.submission_id).map(i => i.submission_id))];
      if (submissionIds.length > 0) {
        const { error: submissionError } = await supabase.from('submissions').update({ invoiced: true }).in('id', submissionIds);
        if (submissionError) throw submissionError;
      }

      let nextInvoice = invoice;
      if (status === 'sent') {
        try {
          const dueDate = new Date(net30).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
          const payUrl = `https://portal.fourgebranding.com/pay/${encodeURIComponent(invoiceNumber)}`;
          const invoiceForPdf = { ...invoice, status: 'sent' };
          const pdfItems = validItems.map(item => ({
            description: item.description,
            quantity: Number(item.quantity) || 1,
            unit_price: Number(item.unit_price) || 0,
          }));
          const emailData = {
            invoiceNumber,
            billTo: billTo || selectedCompany.name,
            total: `$${total.toFixed(2)}`,
            dueDate,
            payUrl,
            notes: notes || '',
          };

          let attachments = [];
          let attachmentWarning = '';
          try {
            const invoicePdf = await withTimeout(
              generateInvoicePDF(invoiceForPdf, selectedCompany, pdfItems, { save: false }),
              8000,
              'Invoice PDF generation'
            );
            const attachment = await withTimeout(
              blobToEmailAttachment(invoicePdf, `${invoiceNumber}.pdf`),
              5000,
              'Invoice attachment encoding'
            );
            attachments = [attachment];
          } catch (attachmentError) {
            console.error('Invoice PDF attachment skipped during creation:', attachmentError);
            attachmentWarning = ' The invoice email was sent without the PDF attachment.';
          }

          await withTimeout(
            sendEmail('invoice_sent', invoiceEmail.trim(), emailData, attachments),
            12000,
            'Sending invoice email'
          );

          const { data: sentInvoice, error: sentError } = await supabase
            .from('invoices')
            .update({ status: 'sent' })
            .eq('id', invoice.id)
            .select()
            .single();
          if (sentError) throw sentError;
          nextInvoice = sentInvoice || { ...invoice, status: 'sent' };
          if (attachmentWarning) {
            alert(`Invoice sent successfully.${attachmentWarning}`);
          }
        } catch (sendError) {
          console.error('Failed to send invoice during creation:', sendError);
          alert(`Invoice was saved as a draft, but the email was not sent: ${sendError.message}`);
        }
      }

      navigate(`/invoices/${invoice.id}`, { state: { invoice: nextInvoice } });
    } catch (saveError) {
      console.error('Failed to save invoice:', saveError);
      alert(`Failed to save invoice: ${saveError.message || 'Unknown error'}`);
    } finally {
      setSaving(false);
    }
  };

  const selectedCompany = companies.find(c => c.id === selectedCompanyId);

  return (
    <Layout>
      <button className="back-link" onClick={() => navigate('/invoices')}>← Back to Invoices</button>

      <div className="page-header">
        <div>
          <div className="page-title">New Invoice</div>
          <div className="page-subtitle">Invoice date: {new Date(today).toLocaleDateString()} · Due: {new Date(net30).toLocaleDateString()} (Net 30)</div>
        </div>
      </div>

      <div className="card" style={{ marginBottom: 24 }}>
        <div className="card-title">Company</div>
        <div className="form-group">
          <label>Select Company *</label>
          <select value={selectedCompanyId} onChange={e => setSelectedCompanyId(e.target.value)}>
            <option value="">Choose a company...</option>
            {companies.map(c => (
              <option key={c.id} value={c.id}>{c.name}</option>
            ))}
          </select>
        </div>
        {selectedCompany && (
          <div className="grid-2" style={{ marginTop: 12 }}>
            <div className="form-group" style={{ marginBottom: 0 }}>
              <label>Bill To</label>
              <input
                type="text"
                value={billTo}
                onChange={e => setBillTo(e.target.value)}
                placeholder={selectedCompany.name}
              />
            </div>
            <div className="form-group" style={{ marginBottom: 0 }}>
              <label>Email To</label>
              <input
                type="email"
                list="company-invoice-recipients"
                value={invoiceEmail}
                onChange={e => setInvoiceEmail(e.target.value)}
                placeholder={companyRecipients[0]?.email || 'client@example.com'}
              />
              <datalist id="company-invoice-recipients">
                {companyRecipients.map(recipient => (
                  <option key={recipient.id} value={recipient.email}>
                    {recipient.name ? `${recipient.name} (${recipient.role})` : recipient.role}
                  </option>
                ))}
              </datalist>
            </div>
          </div>
        )}
      </div>

      <div className="card" style={{ marginBottom: 24 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <div className="card-title" style={{ marginBottom: 0 }}>Unbilled New Requests</div>
          {uninvoicedTasks.length > 0 && !loadingTasks && (
            <button
              className="btn btn-outline btn-sm"
              onClick={() => uninvoicedTasks.forEach(task => { if (!items.some(i => i.task_id === task.id && !i.submission_id)) addTaskAsItem(task); })}
            >
              + Add All
            </button>
          )}
        </div>
        {!selectedCompanyId ? (
          <p style={{ fontSize: 13, color: 'var(--text-muted)' }}>Select a company to see their unbilled requests.</p>
        ) : loadingTasks ? (
          <p style={{ fontSize: 13, color: 'var(--text-muted)' }}>Loading...</p>
        ) : uninvoicedTasks.length === 0 ? (
          <p style={{ fontSize: 13, color: 'var(--text-muted)' }}>No unbilled new requests.</p>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {uninvoicedTasks.map(task => {
              const price = priceList.find(p => p.service_type === task.service_type && p.price_type === 'new');
              const alreadyAdded = items.some(i => i.task_id === task.id && !i.submission_id);
              return (
                <div key={task.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 12px', background: 'var(--bg)', borderRadius: 6, border: '1px solid var(--border)' }}>
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 600 }}>{buildNewItemDescription(task)}</div>
                    <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                      {task.service_type || 'Other'} • {price ? `$${Number(price.price).toFixed(2)}` : 'No price set'}
                    </div>
                  </div>
                  <button
                    className={`btn btn-sm ${alreadyAdded ? 'btn-outline' : 'btn-primary'}`}
                    onClick={() => !alreadyAdded && addTaskAsItem(task)}
                    disabled={alreadyAdded}
                  >
                    {alreadyAdded ? 'Added' : '+ Add'}
                  </button>
                </div>
              );
            })}
          </div>
        )}
      </div>

      {selectedCompanyId && (uninvoicedRevisions.length > 0 || loadingTasks) && (
        <div className="card" style={{ marginBottom: 24 }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
            <div className="card-title" style={{ marginBottom: 0 }}>Unbilled Client Revisions</div>
            {uninvoicedRevisions.length > 0 && !loadingTasks && (
              <button
                className="btn btn-outline btn-sm"
                onClick={() => uninvoicedRevisions.forEach(rev => { if (!items.some(i => i.submission_id === rev.id)) addRevisionAsItem(rev); })}
              >
                + Add All
              </button>
            )}
          </div>
          {loadingTasks ? (
            <p style={{ fontSize: 13, color: 'var(--text-muted)' }}>Loading...</p>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {uninvoicedRevisions.map(rev => {
                const revServiceType = getRevisionServiceType(rev);
                const price = priceList.find(p => p.service_type === revServiceType && p.price_type === 'revision');
                const alreadyAdded = items.some(i => i.submission_id === rev.id);
                return (
                  <div key={rev.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 12px', background: 'var(--bg)', borderRadius: 6, border: '1px solid var(--border)' }}>
                    <div>
                      <div style={{ fontSize: 13, fontWeight: 600 }}>{buildRevisionItemDescription(rev)}</div>
                      <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                        {revServiceType || 'Other'} • {price ? `$${Number(price.price).toFixed(2)}` : 'No price set'}
                      </div>
                    </div>
                    <button
                      className={`btn btn-sm ${alreadyAdded ? 'btn-outline' : 'btn-primary'}`}
                      onClick={() => !alreadyAdded && addRevisionAsItem(rev)}
                      disabled={alreadyAdded}
                    >
                      {alreadyAdded ? 'Added' : '+ Add'}
                    </button>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      )}

      <div className="card" style={{ marginBottom: 24 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <div className="card-title" style={{ marginBottom: 0 }}>Line Items</div>
          {items.some(i => i.description) && (
            <select
              onChange={e => { if (e.target.value) { sortItems(e.target.value); e.target.value = ''; } }}
              defaultValue=""
              style={{ fontSize: 12, padding: '4px 8px', borderRadius: 6, border: '1px solid var(--border)', background: 'var(--card-bg)', color: 'var(--text-primary)', cursor: 'pointer' }}
            >
              <option value="" disabled>Sort by…</option>
              <option value="new-first">New first</option>
              <option value="revision-first">Revision first</option>
              <option value="az">Description A–Z</option>
            </select>
          )}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '20px 90px 1fr 80px 120px 120px 40px', gap: 8, marginBottom: 8 }}>
          {['', 'Type', 'Description', 'Qty', 'Unit Price', 'Total', ''].map((h, i) => (
            <div key={i} style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: 'var(--text-muted)', textAlign: i > 3 ? 'right' : 'left' }}>{h}</div>
          ))}
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {items.map((item, index) => (
            <div
              key={item.id}
              onDragOver={e => e.preventDefault()}
              onDrop={() => handleDrop(index)}
              style={{ display: 'grid', gridTemplateColumns: '20px 90px 1fr 80px 120px 120px 40px', gap: 8, alignItems: 'center' }}
            >
              <div
                draggable
                onDragStart={e => { dragItem.current = index; e.dataTransfer.effectAllowed = 'move'; }}
                style={{ cursor: 'grab', color: 'var(--text-muted)', fontSize: 14, textAlign: 'center', userSelect: 'none' }}
              >⠿</div>
              <span className={`badge ${item.submission_id ? 'badge-client_revision' : 'badge-initial'}`}>
                {item.submission_id ? 'Revision' : 'New'}
              </span>
              <input type="text" placeholder="Description..." value={item.description} onChange={e => updateItem(item.id, 'description', e.target.value)} style={{ margin: 0 }} />
              <input type="number" min="1" value={item.quantity} onChange={e => updateItem(item.id, 'quantity', e.target.value)} style={{ margin: 0, textAlign: 'center' }} />
              <input type="number" min="0" step="0.01" placeholder="0.00" value={item.unit_price} onChange={e => updateItem(item.id, 'unit_price', e.target.value)} style={{ margin: 0, textAlign: 'right' }} />
              <div style={{ textAlign: 'right', fontSize: 14, fontWeight: 600, color: 'var(--text-primary)', paddingRight: 4 }}>
                ${((Number(item.quantity) || 0) * (Number(item.unit_price) || 0)).toFixed(2)}
              </div>
              <button onClick={() => removeItem(item.id)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--danger)', fontSize: 16, padding: 4 }}>✕</button>
            </div>
          ))}
        </div>

        <button className="btn btn-outline btn-sm" style={{ marginTop: 12 }} onClick={() => setItems(prev => [...prev, newItem()])}>
          + Add Line Item
        </button>

        <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 20, paddingTop: 16, borderTop: '1px solid var(--border)' }}>
          <div style={{ textAlign: 'right' }}>
            <div style={{ fontSize: 11, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.5px', color: 'var(--text-muted)', marginBottom: 4 }}>Total</div>
            <div style={{ fontSize: 26, fontWeight: 700, color: 'var(--accent)' }}>${total.toFixed(2)}</div>
          </div>
        </div>
      </div>

      <div className="card" style={{ marginBottom: 24 }}>
        <div className="card-title">Notes</div>
        <textarea placeholder="Additional notes, payment instructions, or terms..." value={notes} onChange={e => setNotes(e.target.value)} style={{ minHeight: 80 }} />
      </div>

      <div className="action-buttons">
        <button className="btn btn-outline" onClick={() => handleSave('draft')} disabled={saving}>Save Draft</button>
        <LoadingButton className="btn btn-primary" onClick={() => handleSave('sent')} loading={saving} loadingText="Finalizing & Sending...">
          Finalise & Send
        </LoadingButton>
        <button className="btn btn-outline" onClick={() => navigate('/invoices')}>Cancel</button>
      </div>
    </Layout>
  );
}
