import React, { createContext, useContext, useState } from 'react';
import { StoreDatabase, Product, ProductVariant, InboundRecord, OutboundRecord, Transaction, SalesReturn, Supplier } from '../types';
import { INITIAL_DATABASE } from '../data/initialData';
import {
  productService,
  inboundService,
  outboundService,
  transactionService,
  returnService,
  masterDataService
} from '../services';
import { ProcessReturnInput } from '../modules/return/return.repository';

interface StoreContextType {
  db: StoreDatabase;
  activeTab: string;
  setActiveTab: (tab: string) => void;
  // Product & Variant CRUD
  addProduct: (product: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>) => Product;
  updateProduct: (id: string, product: Partial<Product>) => void;
  deleteProduct: (id: string) => void;
  addVariant: (productId: string, variant: Omit<ProductVariant, 'id'>) => void;
  updateVariant: (productId: string, variantId: string, variant: Partial<ProductVariant>) => void;
  deleteVariant: (productId: string, variantId: string) => void;
  // Inbound CRUD
  addInboundRecord: (record: Omit<InboundRecord, 'id'>, priceUpdates?: { sellPrice?: number; wholesalePrice?: number }) => void;
  deleteInboundRecord: (id: string) => void;
  // Outbound / Expired / Damaged CRUD
  addOutboundRecord: (record: Omit<OutboundRecord, 'id'>) => void;
  deleteOutboundRecord: (id: string) => void;
  // Transactions
  addTransaction: (transaction: Omit<Transaction, 'id' | 'transactionCode' | 'date'>) => Transaction;
  deleteTransaction: (id: string) => void;
  // Sales Returns
  processSalesReturn: (input: ProcessReturnInput) => SalesReturn;
  deleteSalesReturn: (id: string) => void;
  // Suppliers
  addSupplier: (supplier: Omit<Supplier, 'id'>) => void;
  updateSupplier: (id: string, supplier: Partial<Supplier>) => void;
  deleteSupplier: (id: string) => void;
  // Master Data CRUD
  addMasterCategory: (name: string, description?: string) => void;
  updateMasterCategory: (id: string, name: string, description?: string) => void;
  deleteMasterCategory: (id: string) => void;
  addMasterUnit: (name: string, description?: string) => void;
  updateMasterUnit: (id: string, name: string, description?: string) => void;
  deleteMasterUnit: (id: string) => void;
  addMasterSize: (name: string, description?: string) => void;
  updateMasterSize: (id: string, name: string, description?: string) => void;
  deleteMasterSize: (id: string) => void;
  // Helpers & Validation
  findVariantByBarcode: (barcode: string) => { product: Product; variant: ProductVariant } | null;
  checkDuplicateBarcode: (barcode: string, excludeVariantId?: string) => { isDuplicate: boolean; matchedProduct?: Product; matchedVariant?: ProductVariant };
  // Quick Search state trigger for global scanner
  scannerModalOpen: boolean;
  setScannerModalOpen: (open: boolean) => void;
  priceCheckBarcode: string | null;
  setPriceCheckBarcode: (barcode: string | null) => void;
  mobileMenuOpen: boolean;
  setMobileMenuOpen: (open: boolean) => void;
  isSidebarCollapsed: boolean;
  setIsSidebarCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
  toggleSidebar: () => void;
  masterModalOpen: boolean;
  setMasterModalOpen: (open: boolean) => void;
  outboundModalOpen: boolean;
  setOutboundModalOpen: (open: boolean) => void;
  installModalOpen: boolean;
  setInstallModalOpen: (open: boolean) => void;
  dbStatusModalOpen: boolean;
  setDbStatusModalOpen: (open: boolean) => void;
  // Database Backup / Export / Import / Reset
  exportDatabaseToJson: () => void;
  importDatabaseFromJson: (importedDb: StoreDatabase) => void;
  resetDatabaseToDefault: () => void;
}

const StoreContext = createContext<StoreContextType | undefined>(undefined);

export const StoreProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const sanitizeDatabase = (raw: any): StoreDatabase => {
    return {
      version: raw?.version || '1.0.0',
      storeName: raw?.storeName || 'Toko Makmur',
      lastUpdated: raw?.lastUpdated || new Date().toISOString(),
      suppliers: Array.isArray(raw?.suppliers) ? raw.suppliers : [],
      products: Array.isArray(raw?.products) ? raw.products : [],
      inboundRecords: Array.isArray(raw?.inboundRecords) ? raw.inboundRecords : [],
      transactions: Array.isArray(raw?.transactions) ? raw.transactions : [],
      returns: Array.isArray(raw?.returns) ? raw.returns : [],
      outboundRecords: Array.isArray(raw?.outboundRecords) ? raw.outboundRecords : [],
      categories: Array.isArray(raw?.categories) ? raw.categories : INITIAL_DATABASE.categories,
      units: Array.isArray(raw?.units) ? raw.units : INITIAL_DATABASE.units,
      sizes: Array.isArray(raw?.sizes) ? raw.sizes : INITIAL_DATABASE.sizes,
    };
  };

  // Initial load: check localStorage first for instant display
  const [db, setDb] = useState<StoreDatabase>(() => {
    try {
      const cached = localStorage.getItem('toko_makmur_db');
      if (cached) {
        return sanitizeDatabase(JSON.parse(cached));
      }
    } catch (_e) {}
    return INITIAL_DATABASE;
  });
  const [isLoaded, setIsLoaded] = useState<boolean>(false);

  // Load database from backend (/api/db) on mount
  React.useEffect(() => {
    let isMounted = true;
    fetch('/api/db')
      .then(res => {
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        return res.json();
      })
      .then(data => {
        if (isMounted && data && typeof data === 'object') {
          const sanitized = sanitizeDatabase(data);
          setDb(sanitized);
          try {
            localStorage.setItem('toko_makmur_db', JSON.stringify(sanitized));
          } catch (_e) {}
        }
      })
      .catch(e => {
        console.log('Server /api/db fetch notice:', e.message);
      })
      .finally(() => {
        if (isMounted) setIsLoaded(true);
      });
    return () => { isMounted = false; };
  }, []);

  // Save database to both localStorage (immediately) and server endpoint (debounced)
  React.useEffect(() => {
    if (!isLoaded) return;

    try {
      localStorage.setItem('toko_makmur_db', JSON.stringify(db));
    } catch (_e) {}

    const timer = setTimeout(() => {
      fetch('/api/db', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(db)
      }).catch(err => {
        console.warn('Failed to persist to /api/db server endpoint:', err);
      });
    }, 400);

    return () => clearTimeout(timer);
  }, [db, isLoaded]);

  const exportDatabaseToJson = () => {
    const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(db, null, 2));
    const downloadAnchor = document.createElement('a');
    downloadAnchor.setAttribute("href", dataStr);
    downloadAnchor.setAttribute("download", `toko_makmur_backup_${new Date().toISOString().slice(0, 10)}.json`);
    document.body.appendChild(downloadAnchor);
    downloadAnchor.click();
    downloadAnchor.remove();
  };

  const importDatabaseFromJson = (importedDb: StoreDatabase) => {
    const sanitizedDb = sanitizeDatabase(importedDb);
    setDb(sanitizedDb);
    try {
      localStorage.setItem('toko_makmur_db', JSON.stringify(sanitizedDb));
    } catch (_e) {}
    fetch('/api/db', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(sanitizedDb)
    }).catch(() => {});
  };

  const resetDatabaseToDefault = () => {
    const resetData = sanitizeDatabase(INITIAL_DATABASE);
    setDb(resetData);
    try {
      localStorage.setItem('toko_makmur_db', JSON.stringify(resetData));
    } catch (_e) {}
    fetch('/api/db/reset', { method: 'POST' })
      .then(res => res.json())
      .then(data => {
        const sanitized = sanitizeDatabase(data);
        setDb(sanitized);
        try {
          localStorage.setItem('toko_makmur_db', JSON.stringify(sanitized));
        } catch (_e) {}
      })
      .catch(() => {});
  };

  const [activeTab, setActiveTab] = useState<string>('dashboard');
  const [scannerModalOpen, setScannerModalOpen] = useState<boolean>(false);
  const [priceCheckBarcode, setPriceCheckBarcode] = useState<string | null>(null);
  const [mobileMenuOpen, setMobileMenuOpen] = useState<boolean>(false);
  const [isSidebarCollapsed, setIsSidebarCollapsed] = useState<boolean>(false);
  const [masterModalOpen, setMasterModalOpen] = useState<boolean>(false);
  const [outboundModalOpen, setOutboundModalOpen] = useState<boolean>(false);
  const [installModalOpen, setInstallModalOpen] = useState<boolean>(false);
  const [dbStatusModalOpen, setDbStatusModalOpen] = useState<boolean>(false);

  const toggleSidebar = () => {
    setIsSidebarCollapsed(prev => !prev);
  };

  // Product Actions
  const addProduct = (productData: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>): Product => {
    const { updatedDb, newProduct } = productService.createProduct(db, productData);
    setDb(updatedDb);
    return newProduct;
  };

  const updateProduct = (id: string, productData: Partial<Product>) => {
    setDb(prev => productService.updateProduct(prev, id, productData));
  };

  const deleteProduct = (id: string) => {
    setDb(prev => productService.deleteProduct(prev, id));
  };

  const addVariant = (productId: string, variantData: Omit<ProductVariant, 'id'>) => {
    setDb(prev => productService.addVariant(prev, productId, variantData));
  };

  const updateVariant = (productId: string, variantId: string, variantData: Partial<ProductVariant>) => {
    setDb(prev => productService.updateVariant(prev, productId, variantId, variantData));
  };

  const deleteVariant = (productId: string, variantId: string) => {
    setDb(prev => productService.deleteVariant(prev, productId, variantId));
  };

  // Inbound Actions
  const addInboundRecord = (
    recordData: Omit<InboundRecord, 'id'>,
    priceUpdates?: { sellPrice?: number; wholesalePrice?: number }
  ) => {
    setDb(prev => inboundService.processInboundRecord(prev, recordData, priceUpdates));
  };

  const deleteInboundRecord = (id: string) => {
    setDb(prev => inboundService.deleteInboundRecord(prev, id));
  };

  // Outbound Actions
  const addOutboundRecord = (recordData: Omit<OutboundRecord, 'id'>) => {
    setDb(prev => outboundService.processOutboundRecord(prev, recordData));
  };

  const deleteOutboundRecord = (id: string) => {
    setDb(prev => outboundService.deleteOutboundRecord(prev, id));
  };

  // Transaction Actions
  const addTransaction = (transactionData: Omit<Transaction, 'id' | 'transactionCode' | 'date'>): Transaction => {
    const { updatedDb, newTransaction } = transactionService.createTransaction(db, transactionData);
    setDb(updatedDb);
    return newTransaction;
  };

  const deleteTransaction = (id: string) => {
    setDb(prev => transactionService.deleteTransaction(prev, id));
  };

  // Return Actions
  const processSalesReturn = (input: ProcessReturnInput): SalesReturn => {
    const { updatedDb, newReturn } = returnService.processReturn(db, input);
    setDb(updatedDb);
    return newReturn;
  };

  const deleteSalesReturn = (id: string) => {
    setDb(prev => returnService.deleteReturn(prev, id));
  };

  // Master Data & Suppliers Actions
  const addSupplier = (supplierData: Omit<Supplier, 'id'>) => {
    setDb(prev => masterDataService.addSupplier(prev, supplierData));
  };

  const updateSupplier = (id: string, supplierData: Partial<Supplier>) => {
    setDb(prev => masterDataService.updateSupplier(prev, id, supplierData));
  };

  const deleteSupplier = (id: string) => {
    setDb(prev => masterDataService.deleteSupplier(prev, id));
  };

  const addMasterCategory = (name: string, description?: string) => {
    setDb(prev => masterDataService.addCategory(prev, name, description));
  };

  const updateMasterCategory = (id: string, name: string, description?: string) => {
    setDb(prev => masterDataService.updateCategory(prev, id, name, description));
  };

  const deleteMasterCategory = (id: string) => {
    setDb(prev => masterDataService.deleteCategory(prev, id));
  };

  const addMasterUnit = (name: string, description?: string) => {
    setDb(prev => masterDataService.addUnit(prev, name, description));
  };

  const updateMasterUnit = (id: string, name: string, description?: string) => {
    setDb(prev => masterDataService.updateUnit(prev, id, name, description));
  };

  const deleteMasterUnit = (id: string) => {
    setDb(prev => masterDataService.deleteUnit(prev, id));
  };

  const addMasterSize = (name: string, description?: string) => {
    setDb(prev => masterDataService.addSize(prev, name, description));
  };

  const updateMasterSize = (id: string, name: string, description?: string) => {
    setDb(prev => masterDataService.updateSize(prev, id, name, description));
  };

  const deleteMasterSize = (id: string) => {
    setDb(prev => masterDataService.deleteSize(prev, id));
  };

  // Helpers
  const checkDuplicateBarcode = (barcode: string, excludeVariantId?: string) => {
    return productService.checkDuplicateBarcode(db, barcode, excludeVariantId);
  };

  const findVariantByBarcode = (barcode: string) => {
    return productService.findVariantByBarcode(db, barcode);
  };

  return (
    <StoreContext.Provider
      value={{
        db,
        activeTab,
        setActiveTab,
        addProduct,
        updateProduct,
        deleteProduct,
        addVariant,
        updateVariant,
        deleteVariant,
        addInboundRecord,
        deleteInboundRecord,
        addOutboundRecord,
        deleteOutboundRecord,
        addTransaction,
        deleteTransaction,
        processSalesReturn,
        deleteSalesReturn,
        addSupplier,
        updateSupplier,
        deleteSupplier,
        addMasterCategory,
        updateMasterCategory,
        deleteMasterCategory,
        addMasterUnit,
        updateMasterUnit,
        deleteMasterUnit,
        addMasterSize,
        updateMasterSize,
        deleteMasterSize,
        checkDuplicateBarcode,
        findVariantByBarcode,
        scannerModalOpen,
        setScannerModalOpen,
        priceCheckBarcode,
        setPriceCheckBarcode,
        mobileMenuOpen,
        setMobileMenuOpen,
        isSidebarCollapsed,
        setIsSidebarCollapsed,
        toggleSidebar,
        masterModalOpen,
        setMasterModalOpen,
        outboundModalOpen,
        setOutboundModalOpen,
        installModalOpen,
        setInstallModalOpen,
        dbStatusModalOpen,
        setDbStatusModalOpen,
        exportDatabaseToJson,
        importDatabaseFromJson,
        resetDatabaseToDefault
      }}
    >
      {children}
    </StoreContext.Provider>
  );
};

export const useStore = () => {
  const context = useContext(StoreContext);
  if (!context) {
    throw new Error('useStore must be used within a StoreProvider');
  }
  return context;
};
