// Global store — API-backed with optimistic local state.
// On mount: fetches all data from /api/*. If DB is empty (first run)
// it seeds from window.CKW_SEED then re-fetches.
// Every mutation dispatches immediately (optimistic) and also POSTs to API.

const StoreCtx = React.createContext(null);

function reducer(state, action) {
  switch (action.type) {
    case 'INIT': {
      const products = (action.products || []).map(p => ({
        ...p,
        priority: p.priority || (p.abc === 'A' ? 'high' : p.abc === 'B' ? 'normal' : 'low'),
        flags: p.flags || [],
      }));
      return {
        ...state,
        products,
        movements: action.movements || [],
        anomalies: action.anomalies || [],
        reps: action.reps || [],
        customers: action.customers || [],
        dismissedSuggestions: new Set(action.dismissed || []),
        loading: false,
      };
    }
    case 'UPDATE_PRODUCT': {
      const { sku, patch } = action;
      return {
        ...state,
        products: state.products.map(p =>
          p.sku === sku ? { ...p, ...patch, _flashed: Date.now() } : p
        ),
      };
    }
    case 'DELETE_PRODUCTS': {
      const set = new Set(action.skus);
      return { ...state, products: state.products.filter(p => !set.has(p.sku)) };
    }
    case 'ADD_PRODUCT':
      return { ...state, products: [{ ...action.product }, ...state.products] };
    case 'FLAG_PRODUCTS': {
      const set = new Set(action.skus);
      return {
        ...state,
        products: state.products.map(p =>
          set.has(p.sku)
            ? { ...p, flags: p.flags.includes(action.flag) ? p.flags : [...p.flags, action.flag] }
            : p
        ),
      };
    }
    case 'SET_PRIORITY': {
      const set = new Set(action.skus);
      return {
        ...state,
        products: state.products.map(p =>
          set.has(p.sku) ? { ...p, priority: action.priority } : p
        ),
      };
    }
    case 'RECORD_MOVEMENT': {
      const m = action.movement;
      return {
        ...state,
        movements: [m, ...state.movements],
        products: state.products.map(p => {
          if (p.sku !== m.sku) return p;
          let onHand = p.onHand;
          if (m.type === 'in') onHand = p.onHand + m.qty;
          else if (m.type === 'out') onHand = Math.max(0, p.onHand - m.qty);
          else onHand = m.qty;
          let status = p.status;
          if (p.category !== 'service') {
            if (onHand === 0) status = 'out';
            else if (onHand < p.reorderPoint) status = 'low';
            else if (p.reorderPoint > 0 && onHand > p.reorderPoint * 4) status = 'overstock';
            else status = 'ok';
          }
          return { ...p, onHand, status, _flashed: Date.now() };
        }),
      };
    }
    case 'DISMISS_SUGGESTION': {
      const s = new Set(state.dismissedSuggestions);
      s.add(action.key);
      return { ...state, dismissedSuggestions: s };
    }
    default:
      return state;
  }
}

function StoreProvider({ children }) {
  const [state, dispatch] = React.useReducer(reducer, {
    products: [], movements: [], customers: [],
    anomalies: [], reps: [],
    dismissedSuggestions: new Set(),
    loading: true,
  });

  // Ref so syncDispatch can read pre-mutation state without stale closure
  const stateRef = React.useRef(state);
  React.useEffect(() => { stateRef.current = state; }, [state]);

  // Fire-and-forget API helper
  function apiPost(path, body) {
    return fetch(path, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    }).catch(e => console.warn('API sync failed', path, e));
  }

  // ── Initial load ──────────────────────────────────────────────────────────
  React.useEffect(() => {
    async function load() {
      try {
        const [prodRes, movRes, initRes, disRes] = await Promise.all([
          fetch('/api/products'),
          fetch('/api/movements'),
          fetch('/api/init'),
          fetch('/api/dismissed'),
        ]);
        let products  = await prodRes.json();
        const movs    = await movRes.json();
        const init    = await initRes.json();
        const disKeys = await disRes.json();

        // First run: seed DB from window.CKW_SEED
        if (!Array.isArray(products) || products.length === 0) {
          const seed = window.CKW_SEED || {};
          const initMovs = (seed.recentLines || []).slice(-30).map((l, i) => ({
            id: 'mv-init-' + i,
            date: l.date, type: 'out', sku: l.sku, name: l.name || '',
            qty: l.qty, unit: l.unit || '',
            reason: 'Sales — ' + (l.invoice || ''),
            reference: l.invoice || '', actor: l.rep || '', customer: l.customer || '',
          })).reverse();

          await apiPost('/api/seed', {
            products: seed.products || [],
            movements: initMovs,
            anomalies: seed.anomalies || [],
            reps: seed.reps || [],
          });

          // Re-fetch seeded data
          const [p2, m2, i2, d2] = await Promise.all([
            fetch('/api/products').then(r => r.json()),
            fetch('/api/movements').then(r => r.json()),
            fetch('/api/init').then(r => r.json()),
            fetch('/api/dismissed').then(r => r.json()),
          ]);
          dispatch({ type: 'INIT', products: p2, movements: m2,
            anomalies: i2.anomalies, reps: i2.reps, dismissed: d2 });
          return;
        }

        dispatch({ type: 'INIT', products, movements: movs,
          anomalies: init.anomalies, reps: init.reps, dismissed: disKeys });

      } catch (e) {
        // API unreachable — fall back to in-memory seed (local dev via python server)
        console.warn('API unavailable, using local seed data', e.message);
        const seed = window.CKW_SEED || { products: [], recentLines: [], anomalies: [], reps: [] };
        const products = seed.products.map(p => ({
          ...p,
          priority: p.abc === 'A' ? 'high' : p.abc === 'B' ? 'normal' : 'low',
          flags: [],
        }));
        const movements = seed.recentLines.slice(-30).map((l, i) => ({
          id: 'mv-init-' + i, date: l.date, type: 'out', sku: l.sku, name: l.name || '',
          qty: l.qty, unit: l.unit || '',
          reason: 'Sales — ' + (l.invoice || ''), reference: l.invoice || '', actor: l.rep || '',
        })).reverse();
        dispatch({ type: 'INIT', products, movements,
          anomalies: seed.anomalies || [], reps: seed.reps || [], dismissed: [] });
      }
    }
    load();
  }, []);

  // ── API-synced dispatch ───────────────────────────────────────────────────
  const syncDispatch = React.useCallback((action) => {
    dispatch(action); // optimistic update first

    const cur = stateRef.current;
    switch (action.type) {
      case 'UPDATE_PRODUCT':
        apiPost('/api/products/update', { sku: action.sku, ...action.patch });
        break;
      case 'DELETE_PRODUCTS':
        apiPost('/api/products/delete', { skus: action.skus });
        break;
      case 'ADD_PRODUCT':
        apiPost('/api/products/create', action.product);
        break;
      case 'FLAG_PRODUCTS':
        for (const sku of action.skus) {
          const p = cur.products.find(x => x.sku === sku);
          if (p) {
            const newFlags = p.flags.includes(action.flag)
              ? p.flags
              : [...p.flags, action.flag];
            apiPost('/api/products/update', { sku, flags: newFlags });
          }
        }
        break;
      case 'SET_PRIORITY':
        for (const sku of action.skus) {
          apiPost('/api/products/update', { sku, priority: action.priority });
        }
        break;
      case 'RECORD_MOVEMENT': {
        const m = action.movement;
        apiPost('/api/movements/create', m);
        // Also persist updated onHand + status
        const p = cur.products.find(x => x.sku === m.sku);
        if (p) {
          let onHand = p.onHand;
          if (m.type === 'in') onHand = p.onHand + m.qty;
          else if (m.type === 'out') onHand = Math.max(0, p.onHand - m.qty);
          else onHand = m.qty;
          let status = p.status;
          if (p.category !== 'service') {
            if (onHand === 0) status = 'out';
            else if (onHand < p.reorderPoint) status = 'low';
            else if (p.reorderPoint > 0 && onHand > p.reorderPoint * 4) status = 'overstock';
            else status = 'ok';
          }
          apiPost('/api/products/update', { sku: m.sku, onHand, status });
        }
        break;
      }
      case 'DISMISS_SUGGESTION':
        apiPost('/api/dismissed/add', { key: action.key });
        break;
    }
  }, []);

  return (
    <StoreCtx.Provider value={{ state, dispatch: syncDispatch }}>
      {state.loading ? <LoadingScreen /> : children}
    </StoreCtx.Provider>
  );
}

function LoadingScreen() {
  return (
    <div style={{
      display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center',
      height: '100vh', gap: 16, background: 'var(--bg)',
    }}>
      <div style={{
        width: 52, height: 52, borderRadius: 14,
        background: 'var(--accent)', color: 'white',
        display: 'grid', placeItems: 'center',
        fontWeight: 700, fontSize: 18, letterSpacing: 0.5,
      }}>CKW</div>
      <div style={{ color: 'var(--ink-3)', fontSize: 14 }}>กำลังโหลดข้อมูล…</div>
    </div>
  );
}

function useStore() { return React.useContext(StoreCtx); }
Object.assign(window, { StoreProvider, useStore });
