// Brother Bear — Store + router for the live prototype.
//
// One in-memory store (React Context) + hash-based router. Both are
// optional: if no <StoreProvider> exists in the tree, useStore() returns
// null and screens fall back to default data. That lets the same
// screens.jsx render in both the design canvas (App Home.html) and the
// interactive live view (Live.html).

// ─────────────────────────────────────────────────────────────
// Default mock data — also the canvas's source of truth.
// ─────────────────────────────────────────────────────────────
const DEFAULT_USER = {
  id: 'helgi',
  name: 'Helgi Jonsson',
  handle: '@helgiijons',
  email: 'helgi@brother-bear.com',
  rateFloor: 1200,
  categories: ['Lifestyle', 'Fashion', 'Travel'],
  inboxProvider: 'gmail',
  createdAt: '2026-04-30',
};

const DEFAULT_DEALS = [
  {
    id: '0142', code: 'DEAL · 0142', brand: 'ARMEDANGELS', scope: '3 reels + 2 stories',
    fee: 3500, status: 'awaiting', deadline: 'MAY 14',
    summary: 'ARMEDANGELS reached out for their spring collection. They opened at gifting. We pushed to paid and they returned at €3.500. Exclusivity is the only outstanding item. They want 60 days, you held the line at 28. Brand brief is attached and the deliverables are clear.',
    timeline: [
      { date: 'MAY 09', label: 'Brief delivered',    state: 'done' },
      { date: 'MAY 12', label: 'Negotiation closed', state: 'done' },
      { date: 'MAY 14', label: 'Reels due',          state: 'now'  },
      { date: 'MAY 21', label: 'Stories due',        state: 'next' },
      { date: 'JUN 09', label: 'Exclusivity ends',   state: 'next' },
      { date: 'JUN 30', label: 'Payment expected',   state: 'next' },
    ],
    documents: [
      { code: '01', name: 'Brand brief.pdf',       meta: '4 PAGES' },
      { code: '02', name: 'Contract draft v2.pdf', meta: '7 PAGES' },
      { code: '03', name: 'Email thread',          meta: '12 MESSAGES' },
    ],
  },
  {
    id: '0141', code: 'DEAL · 0141', brand: 'ON RUNNING', scope: '1 longform · 2 reels',
    fee: 5700, status: 'drafting', deadline: 'MAY 28',
    summary: 'ON RUNNING want to feature the Cloudmonster on a long-form review. We countered their first rate. Currently waiting on their revised numbers and a confirmed shoot date.',
    timeline: [
      { date: 'MAY 04', label: 'Brief received',      state: 'done' },
      { date: 'MAY 10', label: 'Counter-offer sent',  state: 'now'  },
      { date: 'MAY 28', label: 'Content due',         state: 'next' },
      { date: 'JUN 15', label: 'Payment expected',    state: 'next' },
    ],
    documents: [
      { code: '01', name: 'Brand brief.pdf',  meta: '6 PAGES' },
      { code: '02', name: 'Email thread',     meta: '8 MESSAGES' },
    ],
  },
  {
    id: '0140', code: 'DEAL · 0140', brand: 'ASKET', scope: '1 reel + static post',
    fee: 2500, status: 'drafting', deadline: 'JUN 02',
    summary: 'ASKET want a quiet-luxury static and one reel. Their first offer was below floor. We pushed and they have come up but not enough. Waiting for one more revision.',
    timeline: [
      { date: 'MAY 06', label: 'Brief received',  state: 'done' },
      { date: 'MAY 11', label: 'Pushed back',     state: 'now'  },
      { date: 'JUN 02', label: 'Content due',     state: 'next' },
    ],
    documents: [
      { code: '01', name: 'Email thread', meta: '5 MESSAGES' },
    ],
  },
  {
    id: '0138', code: 'DEAL · 0138', brand: 'NORSE PROJECTS', scope: '2 reels + 4 stories',
    fee: 2800, status: 'approved', deadline: 'MAY 18',
    summary: 'NORSE PROJECTS approved. Brief signed off. Reels and stories scheduled for the week of May 14.',
    timeline: [
      { date: 'APR 28', label: 'Approved',        state: 'done' },
      { date: 'MAY 18', label: 'Content due',     state: 'next' },
      { date: 'MAY 30', label: 'Payment expected', state: 'next' },
    ],
    documents: [
      { code: '01', name: 'Signed contract.pdf', meta: '5 PAGES' },
      { code: '02', name: 'Brand brief.pdf',     meta: '3 PAGES' },
    ],
  },
  {
    id: '0137', code: 'DEAL · 0137', brand: 'AESOP', scope: '1 longform video',
    fee: 4800, status: 'active', deadline: 'MAY 22',
    summary: 'AESOP body care launch. Long-form video shooting now. Final cut due May 22.',
    timeline: [
      { date: 'APR 20', label: 'Approved',     state: 'done' },
      { date: 'MAY 12', label: 'Shoot day',    state: 'now'  },
      { date: 'MAY 22', label: 'Final cut',    state: 'next' },
      { date: 'JUN 22', label: 'Payment expected', state: 'next' },
    ],
    documents: [
      { code: '01', name: 'Signed contract.pdf', meta: '6 PAGES' },
      { code: '02', name: 'Shoot brief.pdf',     meta: '4 PAGES' },
    ],
  },
];

const DEFAULT_INBOX = [
  { id: 'INC-0142', dealId: '0142', code: 'INC · 0142', brand: 'ARMEDANGELS', subject: "Spring '26 collaboration", preview: 'Hi Helgi, we love your aesthetic and would like to discuss…', status: 'awaiting', time: '12m' },
  { id: 'INC-0141', dealId: '0141', code: 'INC · 0141', brand: 'ON RUNNING',  subject: 'Cloudmonster launch — May',  preview: 'Reaching out about our running shoe drop — interested in…', status: 'drafting', time: '1h' },
  { id: 'INC-0140', dealId: '0140', code: 'INC · 0140', brand: 'ASKET',       subject: 'The Permanent Collection',    preview: 'We work with creators who share our quiet-luxury point of…', status: 'drafting', time: '2h' },
  { id: 'INC-0139',                  code: 'INC · 0139', brand: 'AESOP',       subject: 'Body Care · Q3 release',      preview: 'Following up on rate confirmation. Final brief attached…',     status: 'replied',  time: '4h' },
  { id: 'INC-0136',                  code: 'INC · 0136', brand: 'FINISTERRE',  subject: 'Coastal collection',          preview: 'Happy to confirm closure. Payment scheduled for…',           status: 'closed',   time: '2d' },
];

// Maps human-readable filter chips to internal status values.
const INBOX_FILTERS = {
  'All': null,
  'Awaiting you': 'awaiting',
  'Drafting': 'drafting',
  'Replied': 'replied',
};
const DEALS_FILTERS = {
  'All': null,
  'Awaiting you': 'awaiting',
  'In negotiation': 'drafting',
  'Approved': 'approved',
  'Completed': 'completed',
};

// ─────────────────────────────────────────────────────────────
// Hash router
// ─────────────────────────────────────────────────────────────
function parseRoute(hash) {
  const parts = (hash || '').replace(/^#\/?/, '').split('/').filter(Boolean);
  if (parts.length === 0) return { name: 'inbox' };
  if (parts[0] === 'deals' && parts[1]) return { name: 'deal-detail', dealId: parts[1] };
  if (['inbox', 'deals', 'earnings', 'account'].includes(parts[0])) return { name: parts[0] };
  return { name: 'inbox' };
}

function navigate(path) {
  if (window.location.hash !== path) {
    window.location.hash = path;
  } else {
    // same hash — force a re-emit so back-from-detail to deals refresh works
    window.dispatchEvent(new HashChangeEvent('hashchange'));
  }
}

function useRoute() {
  const [hash, setHash] = React.useState(() => window.location.hash || '#/inbox');
  React.useEffect(() => {
    const onChange = () => setHash(window.location.hash || '#/inbox');
    window.addEventListener('hashchange', onChange);
    return () => window.removeEventListener('hashchange', onChange);
  }, []);
  return parseRoute(hash);
}

// Tab id ↔ route map (used by tab bar + back button)
const TAB_ROUTES = { inbox: '#/inbox', deals: '#/deals', earnings: '#/earnings', account: '#/account' };

// ─────────────────────────────────────────────────────────────
// Store — React Context. Holds mutable app state and exposes
// actions. Screens read state and dispatch actions through the
// useStore() hook.
// ─────────────────────────────────────────────────────────────
const StoreCtx = React.createContext(null);

function useStore() {
  return React.useContext(StoreCtx);
}

function StoreProvider({ children }) {
  const [user]                       = React.useState(DEFAULT_USER);
  const [deals, setDeals]            = React.useState(DEFAULT_DEALS);
  const [inbox, setInbox]            = React.useState(DEFAULT_INBOX);
  const [inboxFilter, setInboxFilter] = React.useState('All');
  const [dealsFilter, setDealsFilter] = React.useState('All');
  const [earningsPeriod, setEarningsPeriod] = React.useState('MTD');
  // Where the user came from when opening a deal — drives the back chevron.
  const [returnTo, setReturnTo] = React.useState('#/deals');

  const filteredInbox = React.useMemo(() => {
    const status = INBOX_FILTERS[inboxFilter];
    if (!status) return inbox;
    return inbox.filter((i) => i.status === status);
  }, [inbox, inboxFilter]);

  const filteredDeals = React.useMemo(() => {
    const status = DEALS_FILTERS[dealsFilter];
    if (!status) return deals;
    return deals.filter((d) => d.status === status);
  }, [deals, dealsFilter]);

  const findDeal = React.useCallback((id) => deals.find((d) => d.id === id), [deals]);

  const openDeal = React.useCallback((id, fromTab) => {
    if (fromTab) setReturnTo(TAB_ROUTES[fromTab] || '#/deals');
    navigate('#/deals/' + id);
  }, []);

  const goBack = React.useCallback(() => navigate(returnTo), [returnTo]);

  const goToTab = React.useCallback((tabId) => navigate(TAB_ROUTES[tabId] || '#/inbox'), []);

  const approveDeal = React.useCallback((id) => {
    setDeals((ds) => ds.map((d) => d.id === id ? { ...d, status: 'approved' } : d));
    setInbox((ix) => ix.map((i) => i.dealId === id ? { ...i, status: 'replied' } : i));
  }, []);

  const declineDeal = React.useCallback((id) => {
    setDeals((ds) => ds.map((d) => d.id === id ? { ...d, status: 'completed' } : d));
    setInbox((ix) => ix.map((i) => i.dealId === id ? { ...i, status: 'closed' } : i));
  }, []);

  const value = React.useMemo(() => ({
    user,
    deals, inbox,
    filteredInbox, filteredDeals,
    inboxFilter, setInboxFilter,
    dealsFilter, setDealsFilter,
    earningsPeriod, setEarningsPeriod,
    findDeal,
    openDeal, goBack, goToTab,
    approveDeal, declineDeal,
  }), [user, deals, inbox, filteredInbox, filteredDeals, inboxFilter, dealsFilter, earningsPeriod, findDeal, openDeal, goBack, goToTab, approveDeal, declineDeal]);

  return <StoreCtx.Provider value={value}>{children}</StoreCtx.Provider>;
}

Object.assign(window, {
  DEFAULT_USER, DEFAULT_DEALS, DEFAULT_INBOX,
  INBOX_FILTERS, DEALS_FILTERS, TAB_ROUTES,
  StoreProvider, useStore,
  useRoute, parseRoute, navigate,
});
