const db = require('../db/models');

const { Op } = db.Sequelize;

const DEFAULT_PRODUCTS = [
  {
    sku: 'SKU-EL-001',
    name: 'Vorta Smart Speaker X1',
    category: 'Elektronik',
    price: 1299000,
    stock: 42,
    reorderPoint: 12,
    reorderPack: 30,
    description: 'Speaker pintar untuk rumah, toko, dan kantor kecil.',
    sold: 318,
    margin: 28,
    trend: 12,
  },
  {
    sku: 'SKU-FA-044',
    name: 'Nusa Everyday Tote',
    category: 'Fashion',
    price: 249000,
    stock: 9,
    reorderPoint: 16,
    reorderPack: 60,
    description: 'Tas kanvas premium untuk kreator dan pekerja mobile.',
    sold: 742,
    margin: 35,
    trend: 18,
  },
  {
    sku: 'SKU-BE-117',
    name: 'Lumin Glow Serum',
    category: 'Beauty',
    price: 189000,
    stock: 24,
    reorderPoint: 20,
    reorderPack: 80,
    description: 'Serum wajah lokal dengan bundling campaign affiliate.',
    sold: 1094,
    margin: 42,
    trend: 25,
  },
  {
    sku: 'SKU-HO-073',
    name: 'Bamboo Desk Organizer',
    category: 'Home Living',
    price: 159000,
    stock: 7,
    reorderPoint: 14,
    reorderPack: 45,
    description: 'Organizer meja kerja dari bambu daur ulang.',
    sold: 286,
    margin: 31,
    trend: -4,
  },
];

const DEFAULT_CUSTOMERS = [
  {
    code: 'CUST-001',
    firstName: 'Alya',
    lastName: 'Paramitha',
    phone: '+62 812 1000 2040',
    email: 'alya@vorta.demo',
    address: 'Jakarta Selatan',
    city: 'Jakarta Selatan',
    province: 'DKI Jakarta',
    segment: 'VIP',
    orders: 18,
    lifetimeValue: 18450000,
  },
  {
    code: 'CUST-002',
    firstName: 'Raka',
    lastName: 'Wijaya',
    phone: '+62 813 4400 8080',
    email: 'raka@vorta.demo',
    address: 'Bandung',
    city: 'Bandung',
    province: 'Jawa Barat',
    segment: 'Reguler',
    orders: 7,
    lifetimeValue: 6390000,
  },
  {
    code: 'CUST-003',
    firstName: 'Sari Nusantara',
    lastName: 'Mart',
    phone: '+62 21 5550 9911',
    email: 'procurement@sarinusa.demo',
    address: 'Surabaya',
    city: 'Surabaya',
    province: 'Jawa Timur',
    segment: 'VIP',
    orders: 31,
    lifetimeValue: 52800000,
  },
  {
    code: 'CUST-004',
    firstName: 'Dimas',
    lastName: 'Kurnia',
    phone: '+62 857 9000 1133',
    email: 'dimas@vorta.demo',
    address: 'Yogyakarta',
    city: 'Yogyakarta',
    province: 'DI Yogyakarta',
    segment: 'Baru',
    orders: 1,
    lifetimeValue: 1299000,
  },
];

const DEFAULT_ORDERS = [
  {
    number: 'ORD-24061',
    customerCode: 'CUST-001',
    total: 1548000,
    shipping: 25000,
    status: 'processing',
    channel: 'Web Store',
    createdAtLabel: 'Hari ini, 09:24',
    placedMinutesAgo: 160,
    paid: true,
    items: [
      { sku: 'SKU-EL-001', quantity: 1 },
      { sku: 'SKU-FA-044', quantity: 1 },
    ],
  },
  {
    number: 'ORD-24062',
    customerCode: 'CUST-002',
    total: 567000,
    shipping: 0,
    status: 'pending_payment',
    channel: 'Marketplace',
    createdAtLabel: 'Hari ini, 10:02',
    placedMinutesAgo: 122,
    paid: false,
    items: [{ sku: 'SKU-BE-117', quantity: 3 }],
  },
  {
    number: 'ORD-24063',
    customerCode: 'CUST-003',
    total: 7950000,
    shipping: 0,
    status: 'shipped',
    channel: 'B2B',
    createdAtLabel: 'Kemarin, 16:48',
    placedMinutesAgo: 1296,
    paid: true,
    items: [{ sku: 'SKU-HO-073', quantity: 50 }],
  },
  {
    number: 'ORD-24064',
    customerCode: 'CUST-004',
    total: 1299000,
    shipping: 0,
    status: 'pending_payment',
    channel: 'Social Commerce',
    createdAtLabel: 'Hari ini, 11:18',
    placedMinutesAgo: 46,
    paid: false,
    items: [{ sku: 'SKU-EL-001', quantity: 1 }],
  },
];

const DEFAULT_PAYMENTS = [
  { reference: 'PAY-8801', orderNumber: 'ORD-24061', method: 'qris', amount: 1548000, status: 'captured' },
  { reference: 'PAY-8802', orderNumber: 'ORD-24062', method: 'bank_transfer', amount: 567000, status: 'initiated' },
  { reference: 'PAY-8803', orderNumber: 'ORD-24063', method: 'card', amount: 7950000, status: 'captured' },
  { reference: 'PAY-8804', orderNumber: 'ORD-24064', method: 'qris', amount: 1299000, status: 'initiated' },
];

const DEFAULT_SHIPMENTS = [
  {
    tracking: 'SHP-7101',
    orderNumber: 'ORD-24061',
    carrier: 'other',
    courier: 'Vorta Express',
    destination: 'Jakarta Selatan',
    eta: 'Hari ini 15:00',
    status: 'ready_to_ship',
    risk: 'Rendah',
  },
  {
    tracking: 'SHP-7102',
    orderNumber: 'ORD-24063',
    carrier: 'dhl',
    courier: 'DHL B2B Freight',
    destination: 'Surabaya',
    eta: 'Besok 12:00',
    status: 'in_transit',
    risk: 'Sedang',
  },
  {
    tracking: 'SHP-7103',
    orderNumber: 'ORD-24064',
    carrier: 'gosend',
    courier: 'GoSend Instant',
    destination: 'Yogyakarta',
    eta: 'Menunggu payment',
    status: 'ready_to_ship',
    risk: 'Rendah',
  },
];

const DEFAULT_CAMPAIGNS = [
  {
    id: 'MKT-501',
    name: 'Payday Electronics Push',
    channel: 'Push',
    budget: 4500000,
    status: 'Aktif',
    conversion: 6.8,
    revenue: 38250000,
  },
  {
    id: 'MKT-502',
    name: 'Beauty Affiliate Sprint',
    channel: 'Affiliate',
    budget: 2800000,
    status: 'Draft',
    conversion: 3.1,
    revenue: 11450000,
  },
  {
    id: 'MKT-503',
    name: 'VIP Repeat Buyer Email',
    channel: 'Email',
    budget: 650000,
    status: 'Selesai',
    conversion: 9.4,
    revenue: 19750000,
  },
];

const DEFAULT_LEDGER = [
  {
    id: 'LOG-1',
    title: 'Payment capture berhasil',
    detail: 'ORD-24061 lunas via QRIS dan siap masuk antrean pick up.',
    time: '2 menit lalu',
    tone: 'success',
  },
  {
    id: 'LOG-2',
    title: 'Low stock alert',
    detail: 'Nusa Everyday Tote dan Bamboo Desk Organizer di bawah reorder point.',
    time: '9 menit lalu',
    tone: 'warning',
  },
  {
    id: 'LOG-3',
    title: 'Campaign aktif',
    detail: 'Payday Electronics Push menghasilkan ROAS awal 8.5x.',
    time: '18 menit lalu',
    tone: 'info',
  },
];

const DEFAULT_SETTINGS = {
  storeName: 'VORTA-COMMERCE HQ',
  currency: 'IDR',
  fulfillmentMode: 'Otomatis',
  lowStockAlert: true,
  paymentAutoCapture: true,
};

const paymentMethodLabels = {
  wallet: 'Wallet',
  bank_transfer: 'VA Bank',
  card: 'Kartu Kredit',
  qris: 'QRIS',
};

const carrierLabels = {
  jne: 'JNE',
  jnt: 'J&T',
  sicepat: 'SiCepat',
  pos: 'POS Indonesia',
  anteraja: 'Anteraja',
  gosend: 'GoSend Instant',
  grabexpress: 'GrabExpress',
  dhl: 'DHL B2B Freight',
  fedex: 'FedEx',
  other: 'Vorta Express',
};

const toNumber = (value) => Number(value || 0);

const slugify = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');

const cloneJson = (value) => JSON.parse(JSON.stringify(value));

const makeImportHash = (name, currentUser) => `vorta-commerce-${name}-${currentUser.id}`;

const getOrganizationId = (currentUser) => (
  currentUser.organizations?.id
  || currentUser.organizationsId
  || currentUser.organizationId
  || null
);

const throwBadRequest = (message) => {
  const error = new Error(message);
  error.code = 400;
  throw error;
};

const mapOrderStatusToUi = (status) => {
  if (['pending_payment'].includes(status)) return 'Baru';
  if (['paid', 'processing'].includes(status)) return 'Diproses';
  if (['shipped'].includes(status)) return 'Dikirim';
  return 'Selesai';
};

const mapPaymentStatusToUi = (status) => {
  if (status === 'captured') return 'Berhasil';
  if (status === 'failed') return 'Gagal';
  if (status === 'refunded') return 'Refund';
  return 'Menunggu';
};

const mapShipmentStatusToUi = (status) => {
  if (['delivered'].includes(status)) return 'Terkirim';
  if (['in_transit', 'out_for_delivery'].includes(status)) return 'Dikirim';
  if (['returned', 'cancelled'].includes(status)) return 'Tahan QC';
  return 'Menunggu Pick Up';
};

const formatDateLabel = (dateValue, fallback) => {
  if (fallback) return fallback;
  if (!dateValue) return 'Baru saja';

  const date = new Date(dateValue);
  const now = new Date();
  const sameDay = date.toDateString() === now.toDateString();
  const yesterday = new Date(now);
  yesterday.setDate(now.getDate() - 1);

  const time = new Intl.DateTimeFormat('id-ID', {
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).format(date);

  if (sameDay) return `Hari ini, ${time}`;
  if (date.toDateString() === yesterday.toDateString()) return `Kemarin, ${time}`;

  return new Intl.DateTimeFormat('id-ID', {
    day: '2-digit',
    month: 'short',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).format(date);
};

class VortaCommerceService {
  static get defaultProductMeta() {
    return DEFAULT_PRODUCTS.reduce((meta, product) => {
      meta[product.sku] = {
        reorderPoint: product.reorderPoint,
        reorderPack: product.reorderPack,
        sold: product.sold,
        margin: product.margin,
        trend: product.trend,
      };
      return meta;
    }, {});
  }

  static get defaultCustomerMeta() {
    return DEFAULT_CUSTOMERS.reduce((meta, customer) => {
      meta[customer.code] = {
        email: customer.email,
        address: customer.address,
        segment: customer.segment,
        orders: customer.orders,
        lifetimeValue: customer.lifetimeValue,
      };
      return meta;
    }, {});
  }

  static pushLedger(ledger, title, detail, tone = 'info') {
    return [
      {
        id: `LOG-${Date.now()}`,
        title,
        detail,
        time: 'Baru saja',
        tone,
      },
      ...(Array.isArray(ledger) ? ledger : []),
    ].slice(0, 8);
  }

  static async getState(currentUser) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);
    });

    return this.buildState(currentUser);
  }

  static async ensureDemoData(currentUser, transaction) {
    const organizationsId = getOrganizationId(currentUser);
    const stateImportHash = makeImportHash('state', currentUser);

    const [state] = await db.vorta_commerce_states.findOrCreate({
      where: { importHash: stateImportHash },
      defaults: {
        userId: currentUser.id,
        organizationsId,
        settings: cloneJson(DEFAULT_SETTINGS),
        campaigns: cloneJson(DEFAULT_CAMPAIGNS),
        ledger: cloneJson(DEFAULT_LEDGER),
        product_meta: this.defaultProductMeta,
        customer_meta: this.defaultCustomerMeta,
        order_meta: {},
        shipment_meta: {},
        importHash: stateImportHash,
        createdById: currentUser.id,
        updatedById: currentUser.id,
      },
      transaction,
    });

    const mergedProductMeta = {
      ...this.defaultProductMeta,
      ...(state.product_meta || {}),
    };
    const mergedCustomerMeta = {
      ...this.defaultCustomerMeta,
      ...(state.customer_meta || {}),
    };

    if (!state.storeId || !state.product_meta || !state.customer_meta) {
      await state.update(
        {
          product_meta: mergedProductMeta,
          customer_meta: mergedCustomerMeta,
          updatedById: currentUser.id,
        },
        { transaction },
      );
    }

    const store = await this.ensureStore(currentUser, state, organizationsId, transaction);
    const categories = await this.ensureCategories(currentUser, organizationsId, transaction);
    const products = await this.ensureProducts(currentUser, store, categories, transaction);
    const customers = await this.ensureCustomers(currentUser, organizationsId, transaction);
    const addresses = await this.ensureAddresses(currentUser, customers, organizationsId, transaction);
    const orders = await this.ensureOrders(currentUser, store, customers, addresses, products, organizationsId, transaction);

    await this.ensurePayments(currentUser, orders, customers, organizationsId, transaction);
    await this.ensureShipments(currentUser, orders, organizationsId, transaction);
  }

  static async ensureStore(currentUser, state, organizationsId, transaction) {
    const importHash = makeImportHash('store', currentUser);
    const settings = {
      ...DEFAULT_SETTINGS,
      ...(state.settings || {}),
    };

    const [store] = await db.stores.findOrCreate({
      where: { importHash },
      defaults: {
        store_name: settings.storeName,
        store_slug: `vorta-commerce-${currentUser.id.slice(0, 8)}`,
        store_type: 'brand',
        status: 'active',
        description: 'Persistent VORTA-COMMERCE demo store backed by the generated commerce entities.',
        support_phone: '+62 21 8888 2026',
        support_email: currentUser.email || 'commerce@vorta.demo',
        ownerId: currentUser.id,
        organizationsId,
        importHash,
        createdById: currentUser.id,
        updatedById: currentUser.id,
      },
      transaction,
    });

    if (!state.storeId || state.storeId !== store.id) {
      await state.update(
        {
          storeId: store.id,
          updatedById: currentUser.id,
        },
        { transaction },
      );
    }

    return store;
  }

  static async ensureCategories(currentUser, organizationsId, transaction) {
    const categories = {};

    for (const product of DEFAULT_PRODUCTS) {
      const importHash = makeImportHash(`category-${slugify(product.category)}`, currentUser);
      const [category] = await db.product_categories.findOrCreate({
        where: { importHash },
        defaults: {
          category_name: product.category,
          category_slug: slugify(product.category),
          visibility: 'public',
          description: `Kategori ${product.category} untuk VORTA-COMMERCE.`,
          organizationsId,
          importHash,
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        transaction,
      });

      categories[product.category] = category;
    }

    return categories;
  }

  static async ensureProducts(currentUser, store, categories, transaction) {
    const products = {};

    for (const product of DEFAULT_PRODUCTS) {
      const importHash = makeImportHash(`product-${product.sku}`, currentUser);
      const category = categories[product.category];
      const costPrice = Math.round(product.price * (1 - product.margin / 100));
      const [record] = await db.products.findOrCreate({
        where: { importHash },
        defaults: {
          product_name: product.name,
          sku: product.sku,
          description: product.description,
          product_type: 'physical',
          price: product.price,
          cost_price: costPrice,
          stock_quantity: product.stock,
          status: product.stock > 0 ? 'active' : 'out_of_stock',
          local_priority_eligible: true,
          storeId: store.id,
          categoryId: category.id,
          organizationsId: store.organizationsId,
          importHash,
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        transaction,
      });

      products[product.sku] = record;
    }

    return products;
  }

  static async ensureCustomers(currentUser, organizationsId, transaction) {
    const customers = {};

    for (const customer of DEFAULT_CUSTOMERS) {
      const importHash = makeImportHash(`customer-${customer.code}`, currentUser);
      const [record] = await db.users.findOrCreate({
        where: { importHash },
        defaults: {
          firstName: customer.firstName,
          lastName: customer.lastName,
          phoneNumber: customer.phone,
          email: customer.email,
          disabled: false,
          emailVerified: true,
          provider: 'local',
          organizationsId,
          importHash,
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        transaction,
      });

      customers[customer.code] = record;
    }

    return customers;
  }

  static async ensureAddresses(currentUser, customers, organizationsId, transaction) {
    const addresses = {};

    for (const customer of DEFAULT_CUSTOMERS) {
      const importHash = makeImportHash(`address-${customer.code}`, currentUser);
      const [address] = await db.addresses.findOrCreate({
        where: { importHash },
        defaults: {
          label: 'Alamat Utama',
          recipient_name: `${customer.firstName} ${customer.lastName}`,
          phone_number: customer.phone,
          country: 'Indonesia',
          province: customer.province,
          city: customer.city,
          district: '-',
          postal_code: '00000',
          street_address: customer.address,
          is_default: true,
          userId: customers[customer.code].id,
          organizationsId,
          importHash,
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        transaction,
      });

      addresses[customer.code] = address;
    }

    return addresses;
  }

  static async ensureOrders(currentUser, store, customers, addresses, products, organizationsId, transaction) {
    const orders = {};

    for (const order of DEFAULT_ORDERS) {
      const importHash = makeImportHash(`order-${order.number}`, currentUser);
      const placedAt = new Date(Date.now() - order.placedMinutesAgo * 60 * 1000);
      const [record] = await db.orders.findOrCreate({
        where: { importHash },
        defaults: {
          order_number: order.number,
          order_status: order.status,
          subtotal_amount: Math.max(order.total - order.shipping, 0),
          shipping_amount: order.shipping,
          total_amount: order.total,
          placed_at: placedAt,
          paid_at: order.paid ? placedAt : null,
          buyer_note: `Channel: ${order.channel}`,
          buyerId: customers[order.customerCode].id,
          storeId: store.id,
          shipping_addressId: addresses[order.customerCode].id,
          organizationsId,
          importHash,
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        transaction,
      });

      for (const item of order.items) {
        const product = products[item.sku];
        const itemImportHash = makeImportHash(`order-item-${order.number}-${item.sku}`, currentUser);
        await db.order_items.findOrCreate({
          where: { importHash: itemImportHash },
          defaults: {
            quantity: item.quantity,
            unit_price: toNumber(product.price),
            line_total: toNumber(product.price) * item.quantity,
            variant_label: item.quantity > 1 ? `${product.product_name} x${item.quantity}` : product.product_name,
            orderId: record.id,
            productId: product.id,
            organizationsId,
            importHash: itemImportHash,
            createdById: currentUser.id,
            updatedById: currentUser.id,
          },
          transaction,
        });
      }

      orders[order.number] = record;
    }

    return orders;
  }

  static async ensurePayments(currentUser, orders, customers, organizationsId, transaction) {
    for (const payment of DEFAULT_PAYMENTS) {
      const order = orders[payment.orderNumber];
      const orderConfig = DEFAULT_ORDERS.find((item) => item.number === payment.orderNumber);
      const customer = customers[orderConfig.customerCode];
      const importHash = makeImportHash(`payment-${payment.reference}`, currentUser);

      await db.payments.findOrCreate({
        where: { importHash },
        defaults: {
          payment_reference: payment.reference,
          method: payment.method,
          status: payment.status,
          amount: payment.amount,
          initiated_at: order.placed_at || new Date(),
          captured_at: payment.status === 'captured' ? order.paid_at || new Date() : null,
          orderId: order.id,
          payerId: customer.id,
          organizationsId,
          importHash,
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        transaction,
      });
    }
  }

  static async ensureShipments(currentUser, orders, organizationsId, transaction) {
    for (const shipment of DEFAULT_SHIPMENTS) {
      const order = orders[shipment.orderNumber];
      const importHash = makeImportHash(`shipment-${shipment.tracking}`, currentUser);

      await db.shipments.findOrCreate({
        where: { importHash },
        defaults: {
          carrier: shipment.carrier,
          tracking_number: shipment.tracking,
          shipment_status: shipment.status,
          shipped_at: ['in_transit', 'out_for_delivery', 'delivered'].includes(shipment.status) ? new Date() : null,
          delivered_at: shipment.status === 'delivered' ? new Date() : null,
          shipping_fee: 25000,
          orderId: order.id,
          organizationsId,
          importHash,
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        transaction,
      });
    }
  }

  static async buildState(currentUser) {
    const state = await db.vorta_commerce_states.findOne({
      where: { importHash: makeImportHash('state', currentUser) },
    });

    if (!state) {
      throwBadRequest('VORTA-COMMERCE state is not initialized.');
    }

    const store = await db.stores.findByPk(state.storeId);

    if (!store) {
      throwBadRequest('VORTA-COMMERCE store is not initialized.');
    }

    const productMeta = {
      ...this.defaultProductMeta,
      ...(state.product_meta || {}),
    };
    const customerMeta = {
      ...this.defaultCustomerMeta,
      ...(state.customer_meta || {}),
    };
    const orderMeta = state.order_meta || {};
    const shipmentMeta = state.shipment_meta || {};

    const products = await db.products.findAll({
      where: { storeId: store.id },
      include: [{ model: db.product_categories, as: 'category' }],
      order: [['sku', 'ASC']],
    });

    const orders = await db.orders.findAll({
      where: { storeId: store.id },
      include: [
        { model: db.users, as: 'buyer' },
        { model: db.order_items, as: 'order_items_order', include: [{ model: db.products, as: 'product' }] },
      ],
      order: [['createdAt', 'DESC']],
    });

    const orderIds = orders.map((order) => order.id);
    const payments = orderIds.length
      ? await db.payments.findAll({ where: { orderId: { [Op.in]: orderIds } }, order: [['createdAt', 'DESC']] })
      : [];
    const shipments = orderIds.length
      ? await db.shipments.findAll({ where: { orderId: { [Op.in]: orderIds } }, order: [['createdAt', 'DESC']] })
      : [];

    const customerRecords = await db.users.findAll({
      where: {
        importHash: {
          [Op.in]: DEFAULT_CUSTOMERS.map((customer) => makeImportHash(`customer-${customer.code}`, currentUser)),
        },
      },
      order: [['createdAt', 'ASC']],
    });

    const customers = DEFAULT_CUSTOMERS.map((defaultCustomer) => {
      const record = customerRecords.find(
        (customer) => customer.importHash === makeImportHash(`customer-${defaultCustomer.code}`, currentUser),
      );
      const meta = customerMeta[defaultCustomer.code] || {};

      return {
        id: defaultCustomer.code,
        name: record ? `${record.firstName || ''} ${record.lastName || ''}`.trim() : `${defaultCustomer.firstName} ${defaultCustomer.lastName}`,
        phone: record?.phoneNumber || defaultCustomer.phone,
        email: record?.email || defaultCustomer.email,
        address: meta.address || defaultCustomer.address,
        segment: meta.segment || defaultCustomer.segment,
        orders: toNumber(meta.orders || defaultCustomer.orders),
        lifetimeValue: toNumber(meta.lifetimeValue || defaultCustomer.lifetimeValue),
      };
    });

    const ordersById = orders.reduce((map, order) => {
      map[order.id] = order;
      return map;
    }, {});
    const paymentsByOrderId = payments.reduce((map, payment) => {
      if (!map[payment.orderId]) map[payment.orderId] = [];
      map[payment.orderId].push(payment);
      return map;
    }, {});
    const shipmentsByOrderId = shipments.reduce((map, shipment) => {
      if (!map[shipment.orderId]) map[shipment.orderId] = [];
      map[shipment.orderId].push(shipment);
      return map;
    }, {});

    const uiProducts = products.map((product) => {
      const meta = productMeta[product.sku] || {};
      const price = toNumber(product.price);
      const costPrice = toNumber(product.cost_price);
      const margin = price ? Math.round(((price - costPrice) / price) * 100) : toNumber(meta.margin);

      return {
        id: product.sku,
        name: product.product_name,
        category: product.category?.category_name || 'Umum',
        price,
        stock: toNumber(product.stock_quantity),
        reorderPoint: toNumber(meta.reorderPoint),
        reorderPack: toNumber(meta.reorderPack),
        description: product.description || '',
        sold: toNumber(meta.sold),
        margin: Number.isFinite(margin) ? margin : toNumber(meta.margin),
        trend: toNumber(meta.trend),
      };
    });

    const uiOrders = orders.map((order) => {
      const payment = paymentsByOrderId[order.id]?.[0];
      const shipment = shipmentsByOrderId[order.id]?.[0];
      const meta = orderMeta[order.order_number] || {};
      const customerCode = DEFAULT_CUSTOMERS.find((customer) => customer.email === order.buyer?.email)?.code || meta.customerId || 'CUST-001';
      const items = (order.order_items_order || []).map((item) => (
        item.variant_label || `${item.product?.product_name || 'Produk'}${item.quantity > 1 ? ` x${item.quantity}` : ''}`
      ));

      return {
        id: order.order_number,
        customerId: customerCode,
        total: toNumber(order.total_amount),
        status: mapOrderStatusToUi(order.order_status),
        paymentStatus: mapPaymentStatusToUi(payment?.status),
        shipmentStatus: mapShipmentStatusToUi(shipment?.shipment_status),
        channel: meta.channel || order.buyer_note?.replace('Channel: ', '') || 'Web Store',
        createdAt: formatDateLabel(order.placed_at, meta.createdAtLabel),
        items,
      };
    });

    const uiPayments = payments.map((payment) => ({
      id: payment.payment_reference,
      orderId: ordersById[payment.orderId]?.order_number || payment.orderId,
      method: paymentMethodLabels[payment.method] || 'QRIS',
      amount: toNumber(payment.amount),
      status: mapPaymentStatusToUi(payment.status),
    }));

    const uiShipments = shipments.map((shipment) => {
      const orderNumber = ordersById[shipment.orderId]?.order_number || shipment.orderId;
      const meta = shipmentMeta[shipment.tracking_number] || {};

      return {
        id: shipment.tracking_number,
        orderId: orderNumber,
        destination: meta.destination || this.destinationForOrder(orderNumber),
        courier: meta.courier || carrierLabels[shipment.carrier] || 'Vorta Express',
        eta: shipment.shipment_status === 'delivered' ? 'Selesai' : meta.eta || 'Hari ini',
        status: mapShipmentStatusToUi(shipment.shipment_status),
        risk: meta.risk || 'Rendah',
      };
    });

    return {
      products: uiProducts,
      customers,
      orders: uiOrders,
      payments: uiPayments,
      shipments: uiShipments,
      campaigns: Array.isArray(state.campaigns) ? state.campaigns : cloneJson(DEFAULT_CAMPAIGNS),
      ledger: Array.isArray(state.ledger) ? state.ledger : cloneJson(DEFAULT_LEDGER),
      settings: {
        ...DEFAULT_SETTINGS,
        ...(state.settings || {}),
      },
      persistedAt: new Date().toISOString(),
    };
  }

  static destinationForOrder(orderNumber) {
    const orderConfig = DEFAULT_ORDERS.find((order) => order.number === orderNumber);
    const customer = DEFAULT_CUSTOMERS.find((item) => item.code === orderConfig?.customerCode);
    return customer?.address || 'Indonesia';
  }

  static async createDemoOrder(currentUser) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      const store = await db.stores.findByPk(state.storeId, { transaction });
      const product = await db.products.findOne({
        where: { storeId: store.id, sku: 'SKU-BE-117' },
        transaction,
      });

      if (!product) throwBadRequest('Produk demo tidak ditemukan.');

      const quantity = 3;
      if (toNumber(product.stock_quantity) < quantity) {
        throwBadRequest(`${product.product_name} tidak punya stok cukup.`);
      }

      const customerConfig = DEFAULT_CUSTOMERS.find((customer) => customer.code === 'CUST-002');
      const customer = await db.users.findOne({
        where: { importHash: makeImportHash('customer-CUST-002', currentUser) },
        transaction,
      });
      const address = await db.addresses.findOne({
        where: { importHash: makeImportHash('address-CUST-002', currentUser) },
        transaction,
      });
      const orderNumber = await this.nextNumber(
        'ORD-',
        db.orders,
        'order_number',
        { storeId: store.id },
        transaction,
        24060,
      );
      const paymentReference = await this.nextNumber(
        'PAY-',
        db.payments,
        'payment_reference',
        { importHash: { [Op.like]: `vorta-commerce-payment-PAY-%-${currentUser.id}` } },
        transaction,
        8800,
      );
      const trackingNumber = await this.nextNumber(
        'SHP-',
        db.shipments,
        'tracking_number',
        { importHash: { [Op.like]: `vorta-commerce-shipment-SHP-%-${currentUser.id}` } },
        transaction,
        7100,
      );
      const shipping = 25000;
      const total = toNumber(product.price) * quantity + shipping;
      const organizationsId = getOrganizationId(currentUser);
      const now = new Date();

      await product.update(
        {
          stock_quantity: toNumber(product.stock_quantity) - quantity,
          updatedById: currentUser.id,
        },
        { transaction },
      );

      const order = await db.orders.create(
        {
          order_number: orderNumber,
          order_status: 'pending_payment',
          subtotal_amount: total - shipping,
          shipping_amount: shipping,
          total_amount: total,
          placed_at: now,
          buyer_note: 'Channel: Social Commerce',
          buyerId: customer.id,
          storeId: store.id,
          shipping_addressId: address.id,
          organizationsId,
          importHash: makeImportHash(`order-${orderNumber}`, currentUser),
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        { transaction },
      );

      await db.order_items.create(
        {
          quantity,
          unit_price: product.price,
          line_total: total - shipping,
          variant_label: `${product.product_name} x${quantity}`,
          orderId: order.id,
          productId: product.id,
          organizationsId,
          importHash: makeImportHash(`order-item-${orderNumber}-${product.sku}`, currentUser),
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        { transaction },
      );

      await db.payments.create(
        {
          payment_reference: paymentReference,
          method: 'qris',
          status: 'initiated',
          amount: total,
          initiated_at: now,
          orderId: order.id,
          payerId: customer.id,
          organizationsId,
          importHash: makeImportHash(`payment-${paymentReference}`, currentUser),
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        { transaction },
      );

      await db.shipments.create(
        {
          carrier: 'other',
          tracking_number: trackingNumber,
          shipment_status: 'ready_to_ship',
          shipping_fee: shipping,
          orderId: order.id,
          organizationsId,
          importHash: makeImportHash(`shipment-${trackingNumber}`, currentUser),
          createdById: currentUser.id,
          updatedById: currentUser.id,
        },
        { transaction },
      );

      const productMeta = {
        ...this.defaultProductMeta,
        ...(state.product_meta || {}),
      };
      const customerMeta = {
        ...this.defaultCustomerMeta,
        ...(state.customer_meta || {}),
      };
      const shipmentMeta = state.shipment_meta || {};
      const orderMeta = state.order_meta || {};

      productMeta[product.sku] = {
        ...(productMeta[product.sku] || {}),
        sold: toNumber(productMeta[product.sku]?.sold) + quantity,
      };
      customerMeta[customerConfig.code] = {
        ...(customerMeta[customerConfig.code] || {}),
        email: customerConfig.email,
        address: customerConfig.address,
        segment: customerConfig.segment,
        orders: toNumber(customerMeta[customerConfig.code]?.orders || customerConfig.orders) + 1,
        lifetimeValue: toNumber(customerMeta[customerConfig.code]?.lifetimeValue || customerConfig.lifetimeValue) + total,
      };
      orderMeta[orderNumber] = {
        channel: 'Social Commerce',
        createdAtLabel: 'Baru saja',
        customerId: customerConfig.code,
      };
      shipmentMeta[trackingNumber] = {
        destination: customerConfig.address,
        courier: 'Vorta Express',
        eta: '6 jam',
        risk: 'Rendah',
      };

      await state.update(
        {
          product_meta: productMeta,
          customer_meta: customerMeta,
          order_meta: orderMeta,
          shipment_meta: shipmentMeta,
          ledger: this.pushLedger(state.ledger, 'Flash order dibuat', `${orderNumber} dibuat dari Social Commerce.`, 'success'),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async nextNumber(prefix, model, column, where, transaction, fallbackNumber) {
    const records = await model.findAll({
      where,
      attributes: [column],
      transaction,
    });
    const maxNumber = records.reduce((max, record) => {
      const raw = record[column] || '';
      const numeric = Number(String(raw).replace(/\D/g, ''));
      return Number.isFinite(numeric) ? Math.max(max, numeric) : max;
    }, fallbackNumber);

    return `${prefix}${maxNumber + 1}`;
  }

  static async restockLowStock(currentUser) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      const store = await db.stores.findByPk(state.storeId, { transaction });
      const products = await db.products.findAll({ where: { storeId: store.id }, transaction });
      const productMeta = {
        ...this.defaultProductMeta,
        ...(state.product_meta || {}),
      };
      const lowStockProducts = products.filter((product) => (
        toNumber(product.stock_quantity) <= toNumber(productMeta[product.sku]?.reorderPoint)
      ));

      if (!lowStockProducts.length) {
        await state.update(
          {
            ledger: this.pushLedger(state.ledger, 'Inventori aman', 'Tidak ada produk di bawah reorder point saat ini.', 'success'),
            updatedById: currentUser.id,
          },
          { transaction },
        );
        return;
      }

      for (const product of lowStockProducts) {
        await product.update(
          {
            stock_quantity: toNumber(product.stock_quantity) + toNumber(productMeta[product.sku]?.reorderPack),
            status: 'active',
            updatedById: currentUser.id,
          },
          { transaction },
        );
      }

      await state.update(
        {
          ledger: this.pushLedger(
            state.ledger,
            'Auto-restock dibuat',
            `${lowStockProducts.length} SKU masuk purchase order otomatis dari inventori.`,
            'success',
          ),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async capturePayment(currentUser, paymentReference) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const payment = await db.payments.findOne({
        where: { payment_reference: paymentReference },
        include: [{ model: db.orders, as: 'order' }],
        transaction,
      });

      if (!payment || payment.order?.storeId !== (await this.currentStoreId(currentUser, transaction))) {
        throwBadRequest('Payment tidak ditemukan.');
      }

      if (payment.status === 'captured') return;

      await payment.update(
        {
          status: 'captured',
          captured_at: new Date(),
          updatedById: currentUser.id,
        },
        { transaction },
      );
      await payment.order.update(
        {
          order_status: payment.order.order_status === 'pending_payment' ? 'processing' : payment.order.order_status,
          paid_at: payment.order.paid_at || new Date(),
          updatedById: currentUser.id,
        },
        { transaction },
      );

      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      await state.update(
        {
          ledger: this.pushLedger(
            state.ledger,
            'Pembayaran sukses',
            `${payment.order.order_number} ditandai lunas via ${paymentMethodLabels[payment.method] || payment.method}.`,
            'success',
          ),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async advanceOrder(currentUser, orderNumber) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const storeId = await this.currentStoreId(currentUser, transaction);
      const order = await db.orders.findOne({
        where: { order_number: orderNumber, storeId },
        transaction,
      });

      if (!order) throwBadRequest('Order tidak ditemukan.');

      const nextStatus = {
        pending_payment: 'processing',
        paid: 'processing',
        processing: 'shipped',
        shipped: 'completed',
        delivered: 'completed',
        completed: 'completed',
        cancelled: 'cancelled',
        refunded: 'refunded',
      }[order.order_status] || 'processing';

      await order.update(
        {
          order_status: nextStatus,
          updatedById: currentUser.id,
        },
        { transaction },
      );

      const shipment = await db.shipments.findOne({ where: { orderId: order.id }, transaction });
      if (shipment) {
        await shipment.update(
          {
            shipment_status: nextStatus === 'shipped' ? 'in_transit' : nextStatus === 'completed' ? 'delivered' : shipment.shipment_status,
            shipped_at: nextStatus === 'shipped' ? new Date() : shipment.shipped_at,
            delivered_at: nextStatus === 'completed' ? new Date() : shipment.delivered_at,
            updatedById: currentUser.id,
          },
          { transaction },
        );
      }

      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      await state.update(
        {
          ledger: this.pushLedger(
            state.ledger,
            'Status pesanan diperbarui',
            `${orderNumber} berpindah ke status ${mapOrderStatusToUi(nextStatus)}.`,
            'info',
          ),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async completeShipment(currentUser, trackingNumber) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const storeId = await this.currentStoreId(currentUser, transaction);
      const shipment = await db.shipments.findOne({
        where: { tracking_number: trackingNumber },
        include: [{ model: db.orders, as: 'order' }],
        transaction,
      });

      if (!shipment || shipment.order?.storeId !== storeId) throwBadRequest('Shipment tidak ditemukan.');
      if (shipment.shipment_status === 'delivered') return;

      await shipment.update(
        {
          shipment_status: 'delivered',
          delivered_at: new Date(),
          updatedById: currentUser.id,
        },
        { transaction },
      );
      await shipment.order.update(
        {
          order_status: 'completed',
          updatedById: currentUser.id,
        },
        { transaction },
      );

      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      const meta = state.shipment_meta?.[trackingNumber] || {};
      await state.update(
        {
          ledger: this.pushLedger(
            state.ledger,
            'Paket terkirim',
            `${shipment.order.order_number} selesai oleh ${meta.courier || carrierLabels[shipment.carrier] || 'kurir'}.`,
            'success',
          ),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async launchCampaign(currentUser, campaignId) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      const campaigns = Array.isArray(state.campaigns) ? state.campaigns : cloneJson(DEFAULT_CAMPAIGNS);
      const campaign = campaigns.find((item) => item.id === campaignId);

      if (!campaign) throwBadRequest('Campaign tidak ditemukan.');

      const updatedCampaigns = campaigns.map((item) => (
        item.id === campaignId
          ? {
              ...item,
              status: 'Aktif',
              conversion: Number((toNumber(item.conversion) + 0.9).toFixed(1)),
              revenue: toNumber(item.revenue) + Math.round(toNumber(item.budget) * 2.4),
            }
          : item
      ));

      await state.update(
        {
          campaigns: updatedCampaigns,
          ledger: this.pushLedger(
            state.ledger,
            'Campaign diluncurkan',
            `${campaign.name} aktif dengan budget IDR ${toNumber(campaign.budget).toLocaleString('id-ID')}.`,
            'success',
          ),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async closeDailyReport(currentUser) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const stateBefore = await this.buildState(currentUser);
      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      const paidRevenue = stateBefore.payments
        .filter((payment) => payment.status === 'Berhasil')
        .reduce((total, payment) => total + payment.amount, 0);
      const lowStockCount = stateBefore.products
        .filter((product) => product.stock <= product.reorderPoint)
        .length;

      await state.update(
        {
          ledger: this.pushLedger(
            state.ledger,
            'Laporan harian dikunci',
            `${stateBefore.orders.length} pesanan, IDR ${paidRevenue.toLocaleString('id-ID')} revenue lunas, ${lowStockCount} SKU perlu perhatian.`,
            'info',
          ),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async updateSettings(currentUser, updates) {
    await db.sequelize.transaction(async (transaction) => {
      await this.ensureDemoData(currentUser, transaction);

      const state = await db.vorta_commerce_states.findOne({
        where: { importHash: makeImportHash('state', currentUser) },
        transaction,
      });
      const settings = {
        ...DEFAULT_SETTINGS,
        ...(state.settings || {}),
        ...updates,
      };
      const store = state.storeId ? await db.stores.findByPk(state.storeId, { transaction }) : null;

      if (store && updates.storeName) {
        await store.update(
          {
            store_name: updates.storeName,
            updatedById: currentUser.id,
          },
          { transaction },
        );
      }

      await state.update(
        {
          settings,
          ledger: this.pushLedger(state.ledger, 'Pengaturan commerce diperbarui', 'Konfigurasi toko disimpan ke database.', 'info'),
          updatedById: currentUser.id,
        },
        { transaction },
      );
    });

    return this.getState(currentUser);
  }

  static async currentStoreId(currentUser, transaction) {
    const state = await db.vorta_commerce_states.findOne({
      where: { importHash: makeImportHash('state', currentUser) },
      transaction,
    });

    if (!state?.storeId) throwBadRequest('Store VORTA-COMMERCE tidak ditemukan.');

    return state.storeId;
  }
}

module.exports = VortaCommerceService;
