// mariusson — simulated payments + orders ledger
//
// In a real deployment this is Stripe (or similar). Here we fake it: card
// fields are validated client-side, then we wait a moment to mimic the
// network round-trip and "succeed" or "decline" deterministically based on
// the test-card number.
//
// Storage key:
//   mariusson:orders   array of order objects keyed by transaction id
//
// Order shape:
//   { id, type, amount, currency, workId, artistId, artistName, buyerId,
//     buyerName, brief, size, note, card: { last4, holder, brand },
//     createdAt, status }
//
// Test cards (so the user can demo failure paths):
//   4242 4242 4242 4242   → succeed
//   4000 0000 0000 0002   → declined
//   4000 0000 0000 0341   → ask for review (then succeed)
// Anything else that passes Luhn + has a 3-digit CVC also succeeds.

(() => {
  const ORDERS_KEY = 'mariusson:orders';

  function readOrders() {
    try {
      const raw = localStorage.getItem(ORDERS_KEY);
      return raw ? JSON.parse(raw) : [];
    } catch { return []; }
  }
  function writeOrders(orders) {
    try { localStorage.setItem(ORDERS_KEY, JSON.stringify(orders)); } catch {}
  }

  function makeTxnId() {
    const r = Math.random().toString(36).slice(2, 8).toUpperCase();
    const t = Date.now().toString(36).slice(-4).toUpperCase();
    return 'TXN-' + r + t;
  }

  // Luhn check — returns true if the digits form a valid card number.
  function luhnOk(num) {
    const digits = String(num).replace(/\D/g, '');
    if (digits.length < 12) return false;
    let sum = 0; let alt = false;
    for (let i = digits.length - 1; i >= 0; i--) {
      let d = parseInt(digits[i], 10);
      if (alt) { d *= 2; if (d > 9) d -= 9; }
      sum += d; alt = !alt;
    }
    return sum % 10 === 0;
  }

  function detectBrand(num) {
    const d = String(num).replace(/\D/g, '');
    if (/^4/.test(d)) return 'Visa';
    if (/^(5[1-5]|2[2-7])/.test(d)) return 'Mastercard';
    if (/^3[47]/.test(d)) return 'Amex';
    if (/^6/.test(d)) return 'Discover';
    return 'Card';
  }

  function validateCard({ number, expMonth, expYear, cvc, holder }) {
    const errs = [];
    if (!holder || !holder.trim()) errs.push('Cardholder name is required');
    const num = String(number || '').replace(/\D/g, '');
    if (!num) errs.push('Card number is required');
    else if (!luhnOk(num)) errs.push('Card number looks invalid');
    const m = parseInt(expMonth, 10);
    const y = parseInt(expYear, 10);
    if (!m || m < 1 || m > 12) errs.push('Expiry month is invalid');
    const fullY = y < 100 ? 2000 + y : y;
    const now = new Date();
    if (!y || fullY < now.getFullYear() || (fullY === now.getFullYear() && m - 1 < now.getMonth())) {
      errs.push('Card is expired');
    }
    if (!/^\d{3,4}$/.test(String(cvc || ''))) errs.push('CVC must be 3 or 4 digits');
    return errs;
  }

  // Pretend network. Resolves with { ok, code, txnId, declineReason? } after
  // a short delay so the UI can show a "processing" state.
  function chargeCard(card, amount) {
    const num = String(card.number || '').replace(/\D/g, '');
    return new Promise((resolve) => {
      setTimeout(() => {
        if (num === '4000000000000002') {
          resolve({ ok: false, declineReason: 'Card declined by issuer' });
        } else if (!amount || amount < 1) {
          resolve({ ok: false, declineReason: 'Amount must be at least €1' });
        } else {
          resolve({ ok: true, txnId: makeTxnId() });
        }
      }, 850 + Math.random() * 600);
    });
  }

  // Process a payment + save the order. Returns the saved order.
  // Two payment paths:
  //   savedCard — a card the user previously saved (we have last4/brand/
  //               holder/exp but NOT the full number or CVC, so we just
  //               trust it and proceed to charge).
  //   card     — a freshly-entered card (full number + CVC, validated).
  async function processPayment({ card, savedCard, amount, type, work, artistName, buyer, extra }) {
    let result, cardSummary;
    if (savedCard) {
      result = { ok: true, txnId: makeTxnId() };
      // Mock-respect the brand/last4 for the receipt
      cardSummary = {
        last4: savedCard.last4,
        holder: savedCard.holder,
        brand: savedCard.brand,
        exp: `${savedCard.expMonth}/${String(savedCard.expYear).slice(-2)}`,
      };
    } else {
      const errs = validateCard(card);
      if (errs.length) throw new Error(errs[0]);
      result = await chargeCard(card, amount);
      if (!result.ok) throw new Error(result.declineReason || 'Payment failed');
      cardSummary = {
        last4: String(card.number).replace(/\D/g, '').slice(-4),
        holder: card.holder,
        brand: detectBrand(card.number),
        exp: `${String(card.expMonth).padStart(2, '0')}/${String(card.expYear).slice(-2)}`,
      };
    }

    const order = {
      id: result.txnId,
      type,
      amount,
      currency: 'EUR',
      workId: work?.id || null,
      workTitle: work?.title || null,
      workImage: work?.image || null,
      artistId: work?.artistId || null,
      artistName: artistName || work?.artist || null,
      buyerId: buyer?.id || null,
      buyerName: buyer?.name || null,
      buyerEmail: buyer?.email || null,
      brief: extra?.brief || null,
      size: extra?.size || null,
      note: extra?.note || null,
      card: cardSummary,
      createdAt: Date.now(),
      status: 'paid',
    };

    const orders = readOrders();
    orders.unshift(order);
    writeOrders(orders);
    window.dispatchEvent(new Event('an-orders-changed'));
    return order;
  }

  function listOrders() { return readOrders(); }
  function listOrdersForBuyer(id) { return readOrders().filter((o) => o.buyerId === id); }
  function listOrdersForArtist(id) { return readOrders().filter((o) => o.artistId === id); }

  function useOrders(filter) {
    const [orders, setOrders] = React.useState(() => readOrders());
    React.useEffect(() => {
      const refresh = () => setOrders(readOrders());
      window.addEventListener('an-orders-changed', refresh);
      window.addEventListener('storage', (e) => { if (e.key === ORDERS_KEY) refresh(); });
      return () => window.removeEventListener('an-orders-changed', refresh);
    }, []);
    if (filter === 'buyer') return orders.filter((o) => o.buyerId === (window.AN_AUTH?.currentAccount()?.id));
    if (filter === 'artist') return orders.filter((o) => o.artistId === (window.AN_AUTH?.currentAccount()?.id));
    return orders;
  }

  // ── Saved cards (collectors) ────────────────────────────────────────
  // Stored under mariusson:cards as an array of {id, ownerId, holder,
  // last4, brand, expMonth, expYear, label}. We never store the full PAN
  // or CVC (this is a mock, but still). Cards persist per user, are
  // surfaced as quick-pick options in CommissionDialog, and can be
  // managed from the left-side Studio drawer.
  const CARDS_KEY = 'mariusson:cards';

  function readCards() {
    try { return JSON.parse(localStorage.getItem(CARDS_KEY) || '[]'); }
    catch { return []; }
  }
  function writeCards(cards) {
    try { localStorage.setItem(CARDS_KEY, JSON.stringify(cards)); } catch {}
  }
  function listCards(ownerId) {
    return readCards().filter((c) => c.ownerId === ownerId);
  }
  function addCard(ownerId, draft) {
    const num = String(draft.number || '').replace(/\D/g, '');
    if (!luhnOk(num)) throw new Error('Card number is invalid');
    const card = {
      id: 'c_' + Math.random().toString(36).slice(2, 10),
      ownerId,
      holder: draft.holder || 'Unnamed',
      last4: num.slice(-4),
      brand: detectBrand(num),
      expMonth: String(draft.expMonth || '').padStart(2, '0'),
      expYear: String(draft.expYear || ''),
      label: draft.label || '',
      createdAt: Date.now(),
    };
    const all = readCards();
    all.push(card);
    writeCards(all);
    window.dispatchEvent(new Event('an-cards-changed'));
    return card;
  }
  function removeCard(id) {
    writeCards(readCards().filter((c) => c.id !== id));
    window.dispatchEvent(new Event('an-cards-changed'));
  }
  function useSavedCards(ownerId) {
    const [cards, setCards] = React.useState(() => listCards(ownerId));
    React.useEffect(() => {
      const refresh = () => setCards(listCards(ownerId));
      refresh();
      window.addEventListener('an-cards-changed', refresh);
      window.addEventListener('storage', (e) => { if (e.key === CARDS_KEY) refresh(); });
      return () => window.removeEventListener('an-cards-changed', refresh);
    }, [ownerId]);
    return cards;
  }

  // ── Payout methods (artists) ────────────────────────────────────────
  // Where artists get paid. Bank wire / IBAN / PayPal / Stripe Connect.
  // Stored as {id, ownerId, kind, label, last4OrTail, holder, country}.
  const PAYOUTS_KEY = 'mariusson:payouts';

  function readPayouts() {
    try { return JSON.parse(localStorage.getItem(PAYOUTS_KEY) || '[]'); }
    catch { return []; }
  }
  function writePayouts(arr) {
    try { localStorage.setItem(PAYOUTS_KEY, JSON.stringify(arr)); } catch {}
  }
  function listPayouts(ownerId) {
    return readPayouts().filter((p) => p.ownerId === ownerId);
  }
  function addPayout(ownerId, draft) {
    if (!draft.kind) throw new Error('Pick a method type');
    const tail = (draft.account || '').replace(/\s+/g, '').slice(-4);
    const payout = {
      id: 'p_' + Math.random().toString(36).slice(2, 10),
      ownerId,
      kind: draft.kind,                // 'bank' | 'iban' | 'paypal' | 'stripe'
      holder: draft.holder || 'Unnamed',
      tail,
      country: draft.country || '',
      label: draft.label || '',
      createdAt: Date.now(),
    };
    const all = readPayouts();
    all.push(payout);
    writePayouts(all);
    window.dispatchEvent(new Event('an-payouts-changed'));
    return payout;
  }
  function removePayout(id) {
    writePayouts(readPayouts().filter((p) => p.id !== id));
    window.dispatchEvent(new Event('an-payouts-changed'));
  }
  function usePayoutMethods(ownerId) {
    const [list, setList] = React.useState(() => listPayouts(ownerId));
    React.useEffect(() => {
      const refresh = () => setList(listPayouts(ownerId));
      refresh();
      window.addEventListener('an-payouts-changed', refresh);
      window.addEventListener('storage', (e) => { if (e.key === PAYOUTS_KEY) refresh(); });
      return () => window.removeEventListener('an-payouts-changed', refresh);
    }, [ownerId]);
    return list;
  }

  window.AN_PAY = {
    processPayment, validateCard, detectBrand,
    listOrders, listOrdersForBuyer, listOrdersForArtist,
    ORDERS_KEY,
    listCards, addCard, removeCard, CARDS_KEY,
    listPayouts, addPayout, removePayout, PAYOUTS_KEY,
  };
  window.useOrders = useOrders;
  window.useSavedCards = useSavedCards;
  window.usePayoutMethods = usePayoutMethods;
})();
