import { useEffect, useMemo, useState } from 'react';
import { type Category, type Transaction, type BalancePoint, createTransaction, getCategories, getTransactions, createCategory, updateTransaction, getBalanceSeries } from '../api';
import AccountPage from './AccountPage';
import AppearancePage from './AppearancePage';
import BalanceChart from './BalanceChart';
import CategoryPieChart from './CategoryPieChart';
import MockBankModal, { type MockGenerationOptions } from './MockBankModal';
import { BACKEND_URL } from '../config';

function formatAmount(n: number) {
  return new Intl.NumberFormat(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(n);
}

export default function Dashboard({ onLogout }: { onLogout: () => void }) {
  const [current, setCurrent] = useState<'home' | 'account' | 'appearance'>('home');
  const [transactions, setTransactions] = useState<Transaction[]>([]);
  const [categories, setCategories] = useState<Category[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [isMockModalOpen, setMockModalOpen] = useState(false);
  const [isGenerating, setIsGenerating] = useState(false);

  // Start CSAS (George) OAuth after login
  async function startOauthCsas() {
    const base = BACKEND_URL.replace(/\/$/, '');
    const url = `${base}/auth/csas/authorize`;
    try {
      const token = localStorage.getItem('token');
      const res = await fetch(url, {
        credentials: 'include',
        headers: token ? { Authorization: `Bearer ${token}` } : undefined,
      });
      const data = await res.json();
      if (data && typeof data.authorization_url === 'string') {
        window.location.assign(data.authorization_url);
      } else {
        alert('Cannot start CSAS OAuth.');
      }
    } catch (e) {
      alert('Cannot start CSAS OAuth.');
    }
  }

  // New transaction form state
  const [amount, setAmount] = useState<string>('');
  const [description, setDescription] = useState('');
  const [selectedCategoryId, setSelectedCategoryId] = useState<number | ''>('');

  // Filters
  const [minAmount, setMinAmount] = useState<string>('');
  const [maxAmount, setMaxAmount] = useState<string>('');
  const [filterCategoryId, setFilterCategoryId] = useState<number | ''>('');
  const [searchText, setSearchText] = useState('');

  // Date-range filter
  const [startDate, setStartDate] = useState<string>(''); // YYYY-MM-DD
  const [endDate, setEndDate] = useState<string>('');

  // Pagination over filtered transactions (20 per page), 0 = latest (most recent)
  const pageSize = 20;
  const [page, setPage] = useState<number>(0);

  // Balance chart series for current date filter
  const [balanceSeries, setBalanceSeries] = useState<BalancePoint[]>([]);

  // Category creation form
  const [newCatName, setNewCatName] = useState('');
  const [newCatDesc, setNewCatDesc] = useState('');

  // New transaction date
  const [txDate, setTxDate] = useState<string>('');

  // Inline edit state for transaction categories
  const [editingTxId, setEditingTxId] = useState<number | null>(null);
  const [editingCategoryIds, setEditingCategoryIds] = useState<number[]>([]);

  async function loadAll() {
    setLoading(true);
    setError(null);
    try {
      const [txs, cats, series] = await Promise.all([
        getTransactions(startDate || undefined, endDate || undefined),
        getCategories(),
        getBalanceSeries(startDate || undefined, endDate || undefined),
      ]);
      setTransactions(txs);
      setCategories(cats);
      setBalanceSeries(series);
      // reset paging to most recent
      setPage(0);
    } catch (err: any) {
      setError(err?.message || 'Failed to load data');
    } finally {
      setLoading(false);
    }
  }

  async function handleGenerateMockTransactions(options: MockGenerationOptions) {
    setIsGenerating(true);
    setMockModalOpen(false);

    const { count, minAmount, maxAmount, startDate, endDate, categoryIds } = options;
    const newTransactions: Transaction[] = [];

    const startDateTime = new Date(startDate).getTime();
    const endDateTime = new Date(endDate).getTime();

    for (let i = 0; i < count; i++) {
      // Generate random data based on user input
      const amount = parseFloat((Math.random() * (maxAmount - minAmount) + minAmount).toFixed(2));

      const randomTime = Math.random() * (endDateTime - startDateTime) + startDateTime;
      const date = new Date(randomTime);
      const dateString = date.toISOString().split('T')[0];

      const randomCategory = categoryIds.length > 0
        ? [categoryIds[Math.floor(Math.random() * categoryIds.length)]]
        : [];

      const payload = {
        amount,
        date: dateString,
        category_ids: randomCategory,
      };

      try {
        const created = await createTransaction(payload);
        newTransactions.push(created);
      } catch (err) {
        console.error("Failed to create mock transaction:", err);
        alert('An error occurred while generating transactions. Check the console.');
        break;
      }
    }

    setIsGenerating(false);
    alert(`${newTransactions.length} mock transactions were successfully generated!`);

    await loadAll();
  }

  useEffect(() => { loadAll(); }, [startDate, endDate]);

  const filtered = useMemo(() => {
    let arr = [...transactions];
    const min = minAmount !== '' ? Number(minAmount) : undefined;
    const max = maxAmount !== '' ? Number(maxAmount) : undefined;
    if (min !== undefined) arr = arr.filter(t => t.amount >= min);
    if (max !== undefined) arr = arr.filter(t => t.amount <= max);
    if (filterCategoryId !== '') arr = arr.filter(t => t.category_ids.includes(filterCategoryId as number));
    if (searchText.trim()) arr = arr.filter(t => (t.description || '').toLowerCase().includes(searchText.toLowerCase()));
    return arr;
  }, [transactions, minAmount, maxAmount, filterCategoryId, searchText]);

  const sortedDesc = useMemo(() => {
    return [...filtered].sort((a, b) => {
      const ad = (a.date || '') > (b.date || '') ? 1 : (a.date || '') < (b.date || '') ? -1 : 0;
      if (ad !== 0) return -ad; // date desc
      return b.id - a.id; // fallback id desc
    });
  }, [filtered]);

  const totalPages = Math.ceil(sortedDesc.length / pageSize);
  const pageStart = page * pageSize;
  const pageEnd = pageStart + pageSize;
  const visible = sortedDesc.slice(pageStart, pageEnd);

  function categoryNameById(id: number) { return categories.find(c => c.id === id)?.name || `#${id}`; }

  async function handleCreate(e: React.FormEvent) {
    e.preventDefault();
    if (!amount) return;
    const payload = {
      amount: Number(amount),
      description: description || undefined,
      category_ids: selectedCategoryId !== '' ? [Number(selectedCategoryId)] : undefined,
      date: txDate || undefined,
    };
    try {
      const created = await createTransaction(payload);
      setTransactions(prev => [created, ...prev]);
      setAmount(''); setDescription(''); setSelectedCategoryId(''); setTxDate('');
    } catch (err: any) {
      alert(err?.message || 'Failed to create transaction');
    }
  }

  function beginEditCategories(t: Transaction) {
    setEditingTxId(t.id);
    setEditingCategoryIds([...(t.category_ids || [])]);
  }
  function cancelEditCategories() {
    setEditingTxId(null);
    setEditingCategoryIds([]);
  }
  async function saveEditCategories() {
    if (editingTxId == null) return;
    try {
      const updated = await updateTransaction(editingTxId, { category_ids: editingCategoryIds });
      setTransactions(prev => prev.map(p => (p.id === updated.id ? updated : p)));
      cancelEditCategories();
    } catch (err: any) {
      alert(err?.message || 'Failed to update transaction categories');
    }
  }

  return (
    <div className="app-layout">
      <aside className="sidebar">
        <div className="logo">7Project</div>
        <nav className="nav">
          <button className={current === 'home' ? 'active' : ''} onClick={() => setCurrent('home')}>Home</button>
          <button className={current === 'account' ? 'active' : ''} onClick={() => setCurrent('account')}>Account</button>
          <button className={current === 'appearance' ? 'active' : ''} onClick={() => setCurrent('appearance')}>Appearance</button>
        </nav>
      </aside>
      <div className="content">
        <div className="topbar">
          <h2 style={{ margin: 0 }}>{current === 'home' ? 'Dashboard' : current === 'account' ? 'Account' : 'Appearance'}</h2>
          <div className="actions">
            <span className="user muted">Signed in</span>
            <button className="btn" onClick={onLogout}>Logout</button>
          </div>
        </div>
        <main className="page space-y">
          {current === 'home' && (
            <>
              <section className="card space-y">
                  <h3>Bank connections</h3>
                  <div className="connection-row">
                    <p className="muted" style={{ margin: 0 }}>Connect your CSAS (George) account.</p>
                    <button className="btn primary" onClick={startOauthCsas}>Connect CSAS (George)</button>
                  </div>
                  <div className="connection-row">
                    <p className="muted" style={{ margin: 0 }}>Generate data from a mock bank.</p>
                    <button className="btn primary" onClick={() => setMockModalOpen(true)}>Connect Mock Bank</button>
                  </div>
              </section>

              <section className="card">
                <h3>Add Transaction</h3>
                <form onSubmit={handleCreate} className="form-row">
                  <input className="input" type="number" step="0.01" placeholder="Amount" value={amount} onChange={(e) => setAmount(e.target.value)} required />
                  <input className="input" type="date" placeholder="Date (optional)" value={txDate} onChange={(e) => setTxDate(e.target.value)} />
                  <input className="input" type="text" placeholder="Description (optional)" value={description} onChange={(e) => setDescription(e.target.value)} />
                  <select className="input" value={selectedCategoryId} onChange={(e) => setSelectedCategoryId(e.target.value ? Number(e.target.value) : '')}>
                    <option value="">No category</option>
                    {categories.map(c => (<option key={c.id} value={c.id}>{c.name}</option>))}
                  </select>
                  <button className="btn primary" type="submit">Add</button>
                </form>
              </section>

              <section className="card">
                <h3>Categories</h3>
                <form className="form-row" onSubmit={async (e) => { e.preventDefault(); if (!newCatName.trim()) return; try { const cat = await createCategory({ name: newCatName.trim(), description: newCatDesc || undefined }); setCategories(prev => [...prev, cat]); setNewCatName(''); setNewCatDesc(''); } catch (err: any) { alert(err?.message || 'Failed to create category'); } }}>
                  <input className="input" type="text" placeholder="New category name" value={newCatName} onChange={(e) => setNewCatName(e.target.value)} />
                  <input className="input" type="text" placeholder="Description (optional)" value={newCatDesc} onChange={(e) => setNewCatDesc(e.target.value)} />
                  <button className="btn primary" type="submit">Create category</button>
                </form>
              </section>

              <section className="card">
                <h3>Filters</h3>
                <div className="form-row" style={{ gap: 8, flexWrap: 'wrap' }}>
                  <input className="input" type="date" placeholder="Start date" value={startDate} onChange={(e) => setStartDate(e.target.value)} />
                  <input className="input" type="date" placeholder="End date" value={endDate} onChange={(e) => setEndDate(e.target.value)} />
                  <input className="input" type="number" step="0.01" placeholder="Min amount" value={minAmount} onChange={(e) => setMinAmount(e.target.value)} />
                  <input className="input" type="number" step="0.01" placeholder="Max amount" value={maxAmount} onChange={(e) => setMaxAmount(e.target.value)} />
                  <select className="input" value={filterCategoryId} onChange={(e) => setFilterCategoryId(e.target.value ? Number(e.target.value) : '')}>
                    <option value="">All categories</option>
                    {categories.map(c => (<option key={c.id} value={c.id}>{c.name}</option>))}
                  </select>
                  <input className="input" type="text" placeholder="Search in description" value={searchText} onChange={(e) => setSearchText(e.target.value)} />
                </div>
              </section>

              <section className="card">
                <h3>Balance over time</h3>
                {loading ? (
                  <div>Loading…</div>
                ) : error ? (
                  <div style={{ color: 'crimson' }}>{error}</div>
                ) : (
                  <BalanceChart data={balanceSeries} />
                )}
              </section>

              {/* 3. Add the new section for the Category Pie Chart */}
              <section className="card">
                {loading ? (
                  <div>Loading…</div>
                ) : error ? (
                  <div style={{ color: 'crimson' }}>{error}</div>
                ) : (
                  // Pass the filtered transactions to see the breakdown for the current view
                  <CategoryPieChart transactions={filtered} categories={categories} />
                )}
              </section>

              <section className="card">
                <h3>Transactions</h3>
                {loading ? (
                  <div>Loading…</div>
                ) : error ? (
                  <div style={{ color: 'crimson' }}>{error}</div>
                ) : filtered.length === 0 ? (
                  <div>No transactions</div>
                ) : (
                  <>
                    <div className="table-controls">
                      <div className="muted">
                        Showing {visible.length} of {filtered.length} (page {Math.min(page + 1, Math.max(1, totalPages))}/{Math.max(1, totalPages)})
                      </div>
                      <div className="actions">
                        <button className="btn primary" disabled={page <= 0} onClick={() => setPage(p => Math.max(0, p - 1))}>Previous</button>
                        <button className="btn primary" disabled={page >= totalPages - 1} onClick={() => setPage(p => Math.min(totalPages - 1, p + 1))}>Next</button>
                      </div>
                    </div>
                    <table className="table">
                      <thead>
                        <tr>
                          <th>Date</th>
                          <th style={{ textAlign: 'right' }}>Amount</th>
                          <th>Description</th>
                          <th>Categories</th>
                        </tr>
                      </thead>
                      <tbody>
                        {visible.map(t => (
                          <tr key={t.id}>
                            <td>{t.date || ''}</td>
                            <td className="amount">{formatAmount(t.amount)}</td>
                            <td>{t.description || ''}</td>
                            <td>
                              {editingTxId === t.id ? (
                                <div className="space-y" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                                  <select multiple className="input" value={editingCategoryIds.map(String)} onChange={(e) => {
                                    const opts = Array.from(e.currentTarget.selectedOptions).map(o => Number(o.value));
                                    setEditingCategoryIds(opts);
                                  }}>
                                    {categories.map(c => (
                                      <option key={c.id} value={c.id}>{c.name}</option>
                                    ))}
                                  </select>
                                  <button className="btn small" onClick={saveEditCategories}>Save</button>
                                    <button className="btn small" onClick={cancelEditCategories}>Cancel</button>
                                </div>
                              ) : (
                                <div className="space-x" style={{ display: 'flex', alignItems: 'center', gap: 8, justifyContent: 'space-between' }}>
                                  <span>{t.category_ids.map(id => categoryNameById(id)).join(', ') || '—'}</span>
                                  <button className="btn small" onClick={() => beginEditCategories(t)}>Change</button>
                                </div>
                              )}
                            </td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </>
                )}
              </section>
            </>
          )}

          {current === 'account' && (
            // lazy import avoided for simplicity
            <AccountPage onDeleted={onLogout} />
          )}

          {current === 'appearance' && (
            <AppearancePage />
          )}
        </main>
      </div>
        <MockBankModal
          isOpen={isMockModalOpen}
          isGenerating={isGenerating}
          categories={categories}
          onClose={() => setMockModalOpen(false)}
          onGenerate={handleGenerateMockTransactions}
        />
    </div>
  );
}
