import {
  collection,
  doc,
  setDoc,
  updateDoc,
  deleteDoc,
  onSnapshot,
  query,
} from 'firebase/firestore';
import { db } from '../lib/firebase';
import { sendOrderConfirmationEmail, sendProcessingEmail, sendDispatchEmail } from './emailService';
import { applyCouponUsage } from './couponService';
import { subscribeFromCheckout } from './newsletterService';

export type OrderStatus = 'Booking' | 'Processing' | 'Dispatched' | 'Delivered' | 'Cancelled';

export interface OrderCustomerInfo {
  name: string;
  companyName?: string;
  email: string;
  phone: string;
  whatsapp?: string;
  address: string;
  city: string;
  province?: string;
  postalCode?: string;
  country?: string;
  notes?: string;
}

export interface OrderItemInfo {
  productId: number | string;
  productName: string;
  image: string;
  strength?: string;
  packing?: string;
  quantity: number;
  unitPrice: number;
  totalPrice: number;
}

export interface OrderTotalsInfo {
  totalItems: number;
  subtotal: number;
  shippingCharges: number;
  discount: number;
  couponCode?: string | null;
  discountPercent?: number;
  grandTotal: number;
}

export interface CourierInfo {
  courierName: 'Leopards' | 'PostEx' | string;
  trackingNumber: string;
  trackingLink: string;
}

export interface EmailStatusInfo {
  confirmationSent: boolean;
  processingSent: boolean;
  dispatchSent: boolean;
  lastSentDate?: string;
  lastError?: string;
}

export interface TimelineEntry {
  status: OrderStatus;
  timestamp: string;
  note: string;
  updatedBy: string;
}

export interface OrderRecord {
  id: string; // Auto-generated e.g. TNL-ORD-849201
  createdAt: string; // ISO date string
  updatedAt: string; // ISO date string
  status: OrderStatus;
  paymentMethod?: 'COD' | 'Bank Transfer' | 'QR Payment';
  bankDetailsUsed?: string;
  qrPaymentAmount?: number;
  paymentProof?: string; // Base64 data URL or image URL
  paymentProofUploadedAt?: string; // ISO date string
  paymentStatus?: 'Pending Verification' | 'Payment Verified' | 'Payment Rejected';
  customer: OrderCustomerInfo;
  items: OrderItemInfo[];
  totals: OrderTotalsInfo;
  courierInfo?: CourierInfo;
  pdfUrl?: string;
  emailStatus: EmailStatusInfo;
  adminNotes?: string;
  timeline: TimelineEntry[];
  wcOrderId?: number;
  wcStoreIndex?: number;
  wcStoreUrl?: string;
}

const ORDERS_STORAGE_KEY = 'tnl_customer_orders_v2';
const ORDERS_COLLECTION = 'orders';

// Default Sample Orders cleared
export const INITIAL_SAMPLE_ORDERS: OrderRecord[] = [];

// In-memory cache
let inMemoryOrdersCache: OrderRecord[] = [];

export function getStoredOrders(): OrderRecord[] {
  if (inMemoryOrdersCache.length > 0) {
    return inMemoryOrdersCache;
  }
  if (typeof window === 'undefined') return [];
  try {
    const raw = localStorage.getItem(ORDERS_STORAGE_KEY);
    if (!raw) {
      saveOrdersLocal([]);
      return [];
    }
    const parsed = JSON.parse(raw) as OrderRecord[];
    if (!Array.isArray(parsed)) {
      saveOrdersLocal([]);
      return [];
    }
    // Filter out residual sample orders
    const nonSample = parsed.filter(o => o.id !== 'TNL-849201' && o.id !== 'TNL-739102');
    if (nonSample.length !== parsed.length) {
      saveOrdersLocal(nonSample);
    }
    inMemoryOrdersCache = nonSample;
    return nonSample;
  } catch (err) {
    console.warn('Failed to parse orders from localStorage:', err);
    return [];
  }
}

export function saveOrdersLocal(orders: OrderRecord[]): void {
  inMemoryOrdersCache = orders;
  if (typeof window === 'undefined') return;
  try {
    localStorage.setItem(ORDERS_STORAGE_KEY, JSON.stringify(orders));
  } catch (err) {
    console.warn('Failed to save orders to localStorage:', err);
  }
}

// Real-time Firestore subscription with local storage fallback and merging
export function subscribeToOrders(onOrdersUpdate: (orders: OrderRecord[]) => void): () => void {
  // Immediately notify with stored orders
  const currentLocal = getStoredOrders();
  onOrdersUpdate(currentLocal);

  try {
    const q = query(collection(db, ORDERS_COLLECTION));
    const unsubscribe = onSnapshot(
      q,
      (snapshot) => {
        const firestoreMap = new Map<string, OrderRecord>();

        snapshot.forEach((docSnap) => {
          const data = docSnap.data() as OrderRecord;
          const id = docSnap.id || data.id;
          if (id) {
            firestoreMap.set(id, {
              ...data,
              id,
              customer: data.customer || { name: 'Customer', email: '', phone: '', address: '', city: 'Karachi' },
              items: data.items || [],
              totals: data.totals || { totalItems: 0, subtotal: 0, shippingCharges: 0, discount: 0, grandTotal: 0 },
              status: data.status || 'Booking',
              createdAt: data.createdAt || new Date().toISOString(),
              updatedAt: data.updatedAt || new Date().toISOString(),
              emailStatus: data.emailStatus || { confirmationSent: false, processingSent: false, dispatchSent: false },
              timeline: data.timeline || [],
            });
          }
        });

        // Merge with existing local orders so local orders aren't wiped out
        const existingLocal = getStoredOrders();
        const mergedMap = new Map<string, OrderRecord>();

        existingLocal.forEach((ord) => {
          if (ord && ord.id) mergedMap.set(ord.id, ord);
        });

        firestoreMap.forEach((ord, id) => {
          mergedMap.set(id, ord);
        });

        const list = Array.from(mergedMap.values());
        list.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());

        saveOrdersLocal(list);
        onOrdersUpdate(list);
      },
      (error) => {
        console.warn('Firestore onSnapshot error for orders, falling back to local storage:', error);
        onOrdersUpdate(getStoredOrders());
      }
    );
    return unsubscribe;
  } catch (err) {
    console.warn('Failed to subscribe to Firestore orders:', err);
    onOrdersUpdate(getStoredOrders());
    return () => {};
  }
}

// Generate unique Order ID
export function generateOrderId(): string {
  const randomDigits = Math.floor(100000 + Math.random() * 900000);
  return `TNL-${randomDigits}`;
}

// Automatically generate tracking link based on courier name & tracking number
export function generateTrackingLink(courierName: string, trackingNumber: string): string {
  const cleanNumber = trackingNumber.trim();
  if (!cleanNumber) return '#';

  // If a full custom URL is provided as tracking number, use it directly
  if (/^https?:\/\//i.test(cleanNumber)) {
    return cleanNumber;
  }

  const cleanCourier = courierName.toLowerCase();

  if (cleanCourier.includes('leopard')) {
    return `https://pk.leopardscourier.com/shipment_tracking_view?cn=${encodeURIComponent(cleanNumber)}`;
  } else if (cleanCourier.includes('postex') || cleanCourier.includes('post ex')) {
    return `https://postex.pk/tracking?cn=${encodeURIComponent(cleanNumber)}`;
  } else if (cleanCourier.includes('tcs')) {
    return `https://www.tcsexpress.com/tracking?trackNo=${encodeURIComponent(cleanNumber)}`;
  } else if (cleanCourier.includes('m&p') || cleanCourier.includes('mnp') || cleanCourier.includes('muller')) {
    return `https://www.mne-express.com/tracking?consignment=${encodeURIComponent(cleanNumber)}`;
  } else if (cleanCourier.includes('trax')) {
    return `https://trax.pk/tracking?cn=${encodeURIComponent(cleanNumber)}`;
  } else if (cleanCourier.includes('call') || cleanCourier.includes('callcourier')) {
    return `https://callcourier.com.pk/tracking/?tc=${encodeURIComponent(cleanNumber)}`;
  } else if (cleanCourier.includes('swyft')) {
    return `https://swyftlogistics.com/track?tracking_id=${encodeURIComponent(cleanNumber)}`;
  } else {
    return `https://www.google.com/search?q=${encodeURIComponent(courierName + ' tracking ' + cleanNumber)}`;
  }
}

// Helper to remove or convert undefined values to null for Firestore compliance
function cleanForFirestore<T>(data: T): any {
  return JSON.parse(
    JSON.stringify(data, (_, v) => (v === undefined ? null : v))
  );
}

// Create & store new order in Firestore
export async function createNewOrder(orderData: {
  customer: OrderCustomerInfo;
  items: OrderItemInfo[];
  totals: OrderTotalsInfo;
  paymentMethod?: 'COD' | 'Bank Transfer' | 'QR Payment';
  bankDetailsUsed?: string;
  qrPaymentAmount?: number;
  paymentProof?: string;
  paymentProofUploadedAt?: string;
  paymentStatus?: 'Pending Verification' | 'Payment Verified' | 'Payment Rejected';
  pdfUrl?: string;
}): Promise<OrderRecord> {
  const orderId = generateOrderId();
  const now = new Date().toISOString();

  const isQr = orderData.paymentMethod === 'QR Payment';

  const newOrder: OrderRecord = {
    id: orderId,
    createdAt: now,
    updatedAt: now,
    status: 'Booking',
    paymentMethod: orderData.paymentMethod || 'COD',
    bankDetailsUsed: orderData.bankDetailsUsed || '',
    qrPaymentAmount: isQr ? (orderData.qrPaymentAmount || orderData.totals.grandTotal) : undefined,
    paymentProof: orderData.paymentProof || undefined,
    paymentProofUploadedAt: orderData.paymentProof ? (orderData.paymentProofUploadedAt || now) : undefined,
    paymentStatus: isQr ? (orderData.paymentStatus || 'Pending Verification') : orderData.paymentStatus,
    customer: orderData.customer,
    items: orderData.items,
    totals: orderData.totals,
    pdfUrl: orderData.pdfUrl || '',
    emailStatus: {
      confirmationSent: false,
      processingSent: false,
      dispatchSent: false,
    },
    adminNotes: '',
    timeline: [
      {
        status: 'Booking',
        timestamp: now,
        note: isQr ? 'Order placed with QR Payment proof uploaded. Pending Verification.' : 'Order placed by customer via website.',
        updatedBy: 'Customer',
      },
    ],
  };

  // Immediate Local Cache update
  const current = getStoredOrders();
  const updated = [newOrder, ...current];
  saveOrdersLocal(updated);

  // Save to Firestore cleanly
  try {
    const firestoreData = cleanForFirestore(newOrder);
    await setDoc(doc(db, ORDERS_COLLECTION, orderId), firestoreData);
    console.log(`Order ${orderId} successfully saved to Firebase Firestore!`);
  } catch (err) {
    console.error('Error saving order to Firestore:', err);
  }

  // Send Order Confirmation Email automatically to Customer & Admin emails
  sendOrderConfirmationEmail(newOrder).then((sent) => {
    if (sent) {
      updateOrderEmailStatus(orderId, 'confirmationSent', true);
    }
  });

  // Apply coupon usage if coupon code was supplied
  if (orderData.totals.couponCode) {
    applyCouponUsage(orderData.totals.couponCode).catch((err) =>
      console.warn('Failed applying coupon usage:', err)
    );
  }

  // Auto Subscribe customer email to newsletter if provided
  if (orderData.customer?.email) {
    subscribeFromCheckout(orderData.customer.email).catch((err) =>
      console.warn('Failed subscribing customer to newsletter from checkout:', err)
    );
  }

  return newOrder;
}

// Update payment verification status
export async function updatePaymentStatus(
  orderId: string,
  newPaymentStatus: 'Pending Verification' | 'Payment Verified' | 'Payment Rejected',
  note?: string
): Promise<OrderRecord | null> {
  const currentOrders = getStoredOrders();
  const existingOrder = currentOrders.find((o) => o.id === orderId);
  if (!existingOrder) return null;

  const now = new Date().toISOString();
  const newTimelineEntry: TimelineEntry = {
    status: existingOrder.status,
    timestamp: now,
    note: note || `Payment Status changed to ${newPaymentStatus}`,
    updatedBy: 'Admin',
  };

  const updatedOrder: OrderRecord = {
    ...existingOrder,
    paymentStatus: newPaymentStatus,
    updatedAt: now,
    timeline: [...(existingOrder.timeline || []), newTimelineEntry],
  };

  // Update local
  const updatedList = currentOrders.map((o) => (o.id === orderId ? updatedOrder : o));
  saveOrdersLocal(updatedList);

  // Update Firestore
  try {
    const orderRef = doc(db, ORDERS_COLLECTION, orderId);
    const updateData = cleanForFirestore({
      paymentStatus: newPaymentStatus,
      updatedAt: now,
      timeline: updatedOrder.timeline,
    });
    await setDoc(orderRef, updateData, { merge: true });
  } catch (err) {
    console.error('Error updating payment status in Firestore:', err);
  }

  return updatedOrder;
}

// Update order status in Firestore and trigger relevant emails
export async function updateOrderStatus(
  orderId: string,
  newStatus: OrderStatus,
  courierData?: { courierName: 'Leopards' | 'PostEx' | string; trackingNumber: string },
  adminNote?: string
): Promise<OrderRecord | null> {
  const currentOrders = getStoredOrders();
  const existingOrder = currentOrders.find((o) => o.id === orderId);
  if (!existingOrder) return null;

  const now = new Date().toISOString();
  let updatedCourierInfo = existingOrder.courierInfo;

  if (newStatus === 'Dispatched' && courierData) {
    const trackingLink = generateTrackingLink(courierData.courierName, courierData.trackingNumber);
    updatedCourierInfo = {
      courierName: courierData.courierName,
      trackingNumber: courierData.trackingNumber,
      trackingLink,
    };
  }

  const newTimelineEntry: TimelineEntry = {
    status: newStatus,
    timestamp: now,
    note: adminNote || `Status changed to ${newStatus}${courierData ? ` via ${courierData.courierName} (Tracking #${courierData.trackingNumber})` : ''}`,
    updatedBy: 'Admin',
  };

  const updatedOrder: OrderRecord = {
    ...existingOrder,
    status: newStatus,
    updatedAt: now,
    courierInfo: updatedCourierInfo,
    adminNotes: adminNote ? `${existingOrder.adminNotes || ''}\n[${new Date().toLocaleDateString()}] ${adminNote}` : existingOrder.adminNotes,
    timeline: [...(existingOrder.timeline || []), newTimelineEntry],
  };

  // Update local
  const updatedList = currentOrders.map((o) => (o.id === orderId ? updatedOrder : o));
  saveOrdersLocal(updatedList);

  // Update Firestore
  try {
    const orderRef = doc(db, ORDERS_COLLECTION, orderId);
    const updateData = cleanForFirestore({
      status: updatedOrder.status,
      updatedAt: updatedOrder.updatedAt,
      courierInfo: updatedOrder.courierInfo || null,
      adminNotes: updatedOrder.adminNotes || '',
      timeline: updatedOrder.timeline,
    });
    await setDoc(orderRef, updateData, { merge: true });
  } catch (err) {
    console.error('Error updating order status in Firestore:', err);
  }

  // Handle Automatic Email Triggers
  if (newStatus === 'Processing' && !updatedOrder.emailStatus.processingSent) {
    sendProcessingEmail(updatedOrder).then((sent) => {
      if (sent) updateOrderEmailStatus(orderId, 'processingSent', true);
    });
  } else if (newStatus === 'Dispatched') {
    sendDispatchEmail(updatedOrder).then((sent) => {
      if (sent) updateOrderEmailStatus(orderId, 'dispatchSent', true);
    });
  }

  return updatedOrder;
}

// Helper to update email status flags inside Firestore & local order
export async function updateOrderEmailStatus(
  orderId: string,
  field: 'confirmationSent' | 'processingSent' | 'dispatchSent',
  value: boolean
): Promise<void> {
  const current = getStoredOrders();
  const order = current.find((o) => o.id === orderId);
  if (!order) return;

  const newEmailStatus: EmailStatusInfo = {
    ...order.emailStatus,
    [field]: value,
    lastSentDate: new Date().toISOString(),
  };

  const updatedOrder = { ...order, emailStatus: newEmailStatus };
  saveOrdersLocal(current.map((o) => (o.id === orderId ? updatedOrder : o)));

  try {
    const orderRef = doc(db, ORDERS_COLLECTION, orderId);
    await setDoc(orderRef, cleanForFirestore({ emailStatus: newEmailStatus }), { merge: true });
  } catch (err) {
    console.warn('Failed to update email status in Firestore:', err);
  }
}

// Re-send email manually from Admin Panel
export async function resendOrderEmail(
  order: OrderRecord,
  emailType: 'confirmation' | 'processing' | 'dispatch'
): Promise<boolean> {
  let success = false;
  if (emailType === 'confirmation') {
    success = await sendOrderConfirmationEmail(order);
    if (success) await updateOrderEmailStatus(order.id, 'confirmationSent', true);
  } else if (emailType === 'processing') {
    success = await sendProcessingEmail(order);
    if (success) await updateOrderEmailStatus(order.id, 'processingSent', true);
  } else if (emailType === 'dispatch') {
    success = await sendDispatchEmail(order);
    if (success) await updateOrderEmailStatus(order.id, 'dispatchSent', true);
  }
  return success;
}

// Save PDF URL into order document
export async function saveOrderPdfUrl(orderId: string, pdfUrl: string): Promise<void> {
  const current = getStoredOrders();
  const updatedList = current.map((o) => (o.id === orderId ? { ...o, pdfUrl } : o));
  saveOrdersLocal(updatedList);

  try {
    const orderRef = doc(db, ORDERS_COLLECTION, orderId);
    await setDoc(orderRef, cleanForFirestore({ pdfUrl: pdfUrl || '' }), { merge: true });
  } catch (err) {
    console.warn('Error updating pdfUrl in Firestore:', err);
  }
}

// Update Admin Notes
export async function updateOrderAdminNotes(orderId: string, adminNotes: string): Promise<void> {
  const current = getStoredOrders();
  const updatedList = current.map((o) => (o.id === orderId ? { ...o, adminNotes } : o));
  saveOrdersLocal(updatedList);

  try {
    const orderRef = doc(db, ORDERS_COLLECTION, orderId);
    await setDoc(orderRef, cleanForFirestore({ adminNotes: adminNotes || '' }), { merge: true });
  } catch (err) {
    console.warn('Error updating admin notes in Firestore:', err);
  }
}
