import { Component, inject, OnInit, OnDestroy, signal, HostListener, effect } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { DialogModule } from 'primeng/dialog';
import { ConfirmationService, MessageService } from 'primeng/api';
import { ToastModule } from 'primeng/toast';
import { PosHeaderComponent } from '../components/pos-header/pos-header.component';
import { ProductGridComponent } from '../components/product-grid/product-grid.component';
import { CartPanelComponent } from '../components/cart-panel/cart-panel.component';
import { NumpadComponent } from '../components/numpad/numpad.component';
import { InvoiceTableComponent } from '../components/invoice-table/invoice-table.component';
import { PosFooterComponent } from '../components/pos-footer/pos-footer.component';
import { PaymentDialogComponent } from '../components/payment-dialog/payment-dialog.component';
import { ReturnDialogComponent } from '../components/return-dialog/return-dialog.component';
import { SessionOpenDialogComponent } from '../components/session-open-dialog/session-open-dialog.component';
import { SessionCloseDialogComponent } from '../components/session-close-dialog/session-close-dialog.component';
import { HeldOrdersDialogComponent } from '../components/held-orders-dialog/held-orders-dialog.component';
import { VariantPickerComponent } from '../components/variant-picker/variant-picker.component';
import { CouponDialogComponent } from '../components/coupon-dialog/coupon-dialog.component';
import { ReceiptPreviewComponent } from '../components/receipt-preview/receipt-preview.component';
import { PosCartService } from '../services/pos-cart.service';
import { PosOfflineService } from '../services/pos-offline.service';
import { PosReceiptService } from '../services/pos-receipt.service';
import { PosSessionService } from '../services/pos-session.service';
import { PosProductService } from '../services/pos-product.service';
import { PosService } from '../services/pos.service';
import { PosHeldOrderService } from '../services/pos-held-order.service';
import { CurrencyService } from '../../../core/services/currency.service';
import {
  PosSession,
  PosProduct,
  PosCategory,
  PosTerminal,
  ConnectionStatus,
  HeldOrder,
} from '../models/pos.model';

@Component({
  selector: 'app-pos-layout',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    TranslateModule,
    ConfirmDialogModule,
    DialogModule,
    ToastModule,
    PosHeaderComponent,
    ProductGridComponent,
    CartPanelComponent,
    NumpadComponent,
    InvoiceTableComponent,
    PosFooterComponent,
    PaymentDialogComponent,
    ReturnDialogComponent,
    SessionOpenDialogComponent,
    SessionCloseDialogComponent,
    HeldOrdersDialogComponent,
    VariantPickerComponent,
    CouponDialogComponent,
    ReceiptPreviewComponent,
  ],
  providers: [ConfirmationService, MessageService],
  templateUrl: './pos-layout.component.html',
  styleUrl: './pos-layout.component.scss',
})
export class PosLayoutComponent implements OnInit, OnDestroy {
  private router = inject(Router);
  private translate = inject(TranslateService);
  private confirm = inject(ConfirmationService);
  private message = inject(MessageService);
  private sessionService = inject(PosSessionService);
  private productService = inject(PosProductService);
  private posService = inject(PosService);
  private heldOrderService = inject(PosHeldOrderService);
  private currencyService = inject(CurrencyService);
  offlineService = inject(PosOfflineService);
  private receiptService = inject(PosReceiptService);
  cartService = inject(PosCartService);

  // State
  session = signal<PosSession | null>(null);
  terminal = signal<PosTerminal | null>(null);
  products = signal<PosProduct[]>([]);
  categories = signal<PosCategory[]>([]);
  selectedCategory = signal<number | null>(null);
  connectionStatus = this.offlineService.connectionStatus;
  pendingCount = this.offlineService.pendingCount;
  loading = signal(true);
  currencySymbol = signal('');
  posLayout = signal<'modern' | 'classic' | 'retail' | 'cashier'>(
    (localStorage.getItem('pos_layout') as 'modern' | 'classic' | 'retail' | 'cashier') || 'cashier'
  );

  // Pagination state for product grid
  productsCurrentPage = signal(1);
  productsLastPage = signal(1);
  productsTotal = signal(0);
  productsLoadingMore = signal(false);
  productsCacheSyncing = signal(false);

  // Dialog visibility
  showSessionOpen = signal(true);
  showSessionClose = signal(false);
  showPayment = signal(false);
  showReturn = signal(false);
  showHeldOrders = signal(false);
  showVariantPicker = signal(false);
  showCoupon = signal(false);
  showReceiptPreview = signal(false);
  lastReceiptHtml = signal('');
  variantProduct = signal<PosProduct | null>(null);

  // Quick cash dialog
  showQuickCash = signal(false);
  cashAmountPaid = signal(0);
  cashChange = signal(0);

  // Payment processing loading
  paymentProcessing = signal(false);

  // On-screen keyboard setting
  onScreenKeyboardEnabled = signal(
    localStorage.getItem('pos_onscreen_keyboard') !== 'false' // enabled by default
  );
  showOnScreenKeyboard = signal(false);
  oskLang = signal<'ar' | 'en' | 'symbols'>('ar');

  // Auto-save cart to localStorage on every change
  private cartSaveEffect = effect(() => {
    const items = this.cartService.items();
    const customerId = this.cartService.customerId();
    const customerName = this.cartService.customerName();
    const coupon = this.cartService.coupon();
    const manualDiscount = this.cartService.manualDiscount();
    if (items.length > 0) {
      this.offlineService.saveCart({ items, customerId, customerName, coupon, manualDiscount });
    } else {
      this.offlineService.clearSavedCart();
    }
  });

  ngOnInit(): void {
    this.checkActiveSession();
    this.loadProducts();
    this.loadCategories();
    this.loadBaseCurrency();
    this.offlineService.initDB().then(() => {
      this.offlineService.startConnectionMonitor();
      this.offlineService.getPendingCount().then((c) => this.offlineService.pendingCount.set(c));
    });
    // Restore cart from backup if any
    this.restoreCartBackup();
  }

  private loadBaseCurrency(): void {
    const cached = localStorage.getItem('pos_currency_symbol');
    if (cached) this.currencySymbol.set(cached);
    this.currencyService.list(1, 50).subscribe({
      next: (res) => {
        const base = res.data.find((c) => c.is_base);
        if (base) {
          this.currencySymbol.set(base.symbol);
          localStorage.setItem('pos_currency_symbol', base.symbol);
          localStorage.setItem('pos_currency_code', base.code);
        }
      },
    });
  }

  private restoreCartBackup(): void {
    const saved = this.offlineService.getSavedCart();
    if (saved?.items?.length) {
      this.cartService.items.set(saved.items);
      if (saved.customerId) {
        this.cartService.setCustomer(saved.customerId, saved.customerName || '');
      }
      if (saved.coupon) {
        this.cartService.coupon.set(saved.coupon);
      }
      if (saved.manualDiscount) {
        this.cartService.manualDiscount.set(saved.manualDiscount);
      }
    }
  }

  ngOnDestroy(): void {
    this.offlineService.stopConnectionMonitor();
  }

  // Keyboard shortcuts
  @HostListener('window:keydown', ['$event'])
  onKeydown(event: KeyboardEvent): void {
    // Skip if user is typing in an input
    const tag = (event.target as HTMLElement)?.tagName;
    if (tag === 'INPUT' || tag === 'TEXTAREA') return;

    const isCashier = this.posLayout() === 'cashier';

    switch (event.key) {
      case 'F1':
        event.preventDefault();
        this.onPaymentRequested();
        break;
      case 'F4':
        if (isCashier) {
          event.preventDefault();
          this.onHoldOrder();
        }
        break;
      case 'F5':
        event.preventDefault();
        this.showReturn.set(true);
        break;
      case 'F6':
        if (!isCashier) {
          event.preventDefault();
          this.onHoldOrder();
        }
        break;
      case 'F10':
        if (isCashier) {
          event.preventDefault();
          this.onPayCash();
        }
        break;
      case 'F11':
        if (isCashier) {
          event.preventDefault();
          this.onPayCard();
        }
        break;
      case 'Escape':
        event.preventDefault();
        if (this.showQuickCash()) this.showQuickCash.set(false);
        else if (this.showPayment()) this.showPayment.set(false);
        else if (this.showReturn()) this.showReturn.set(false);
        else if (this.showHeldOrders()) this.showHeldOrders.set(false);
        else if (this.showCoupon()) this.showCoupon.set(false);
        else if (this.showVariantPicker()) this.showVariantPicker.set(false);
        else if (this.showReceiptPreview()) this.showReceiptPreview.set(false);
        break;
      case 'Delete':
        event.preventDefault();
        const idx = this.cartService.selectedItemIndex();
        if (idx !== null) this.cartService.removeItem(idx);
        break;
    }
  }

  private checkActiveSession(): void {
    this.sessionService.getActiveSession().subscribe({
      next: (res) => {
        if (res.data) {
          this.session.set(res.data);
          this.showSessionOpen.set(false);
          // Cache session for offline use
          this.offlineService.cacheSession(res.data).catch(() => {});
        } else {
          this.showSessionOpen.set(true);
        }
        this.loading.set(false);
      },
      error: () => {
        // Offline fallback: try cached session
        this.offlineService.getCachedSession().then((cached) => {
          if (cached) {
            this.session.set(cached);
            this.showSessionOpen.set(false);
          } else {
            this.showSessionOpen.set(true);
          }
          this.loading.set(false);
        }).catch(() => {
          this.loading.set(false);
          this.showSessionOpen.set(true);
        });
      },
    });
  }

  loadProducts(): void {
    const warehouseId = this.session()?.warehouse?.id;
    const categoryId = this.selectedCategory() ?? undefined;

    // Load first page only (fast initial display)
    this.productService.getProductsPage(1, warehouseId, categoryId).subscribe({
      next: (page) => {
        this.products.set(page.data);
        this.productsCurrentPage.set(page.currentPage);
        this.productsLastPage.set(page.lastPage);
        this.productsTotal.set(page.total);
      },
    });

    // Background: sync all products to IndexedDB for offline/barcode use
    if (!this.productsCacheSyncing()) {
      this.productsCacheSyncing.set(true);
      this.productService.syncAllToCache(warehouseId).subscribe({
        next: () => this.productsCacheSyncing.set(false),
        error: () => this.productsCacheSyncing.set(false),
      });
    }
  }

  loadMoreProducts(): void {
    if (this.productsLoadingMore()) return;
    if (this.productsCurrentPage() >= this.productsLastPage()) return;

    const nextPage = this.productsCurrentPage() + 1;
    const warehouseId = this.session()?.warehouse?.id;
    const categoryId = this.selectedCategory() ?? undefined;

    this.productsLoadingMore.set(true);
    this.productService.getProductsPage(nextPage, warehouseId, categoryId).subscribe({
      next: (page) => {
        this.products.update((current) => [...current, ...page.data]);
        this.productsCurrentPage.set(page.currentPage);
        this.productsLastPage.set(page.lastPage);
        this.productsTotal.set(page.total);
        this.productsLoadingMore.set(false);
      },
      error: () => this.productsLoadingMore.set(false),
    });
  }

  private loadCategories(): void {
    this.productService.getCategories().subscribe({
      next: (cats) => this.categories.set(cats),
    });
  }

  // Event handlers
  onSessionOpened(session: PosSession): void {
    this.session.set(session);
    this.showSessionOpen.set(false);
    this.loadProducts();
    this.offlineService.cacheSession(session).catch(() => {});
  }

  onProductSelected(product: PosProduct): void {
    if (product.has_variants && product.variants?.length) {
      this.variantProduct.set(product);
      this.showVariantPicker.set(true);
    } else {
      this.cartService.addProduct(product);
    }
  }

  onVariantSelected(event: { product: PosProduct; variant: any }): void {
    this.cartService.addProduct(event.product, event.variant);
    this.showVariantPicker.set(false);
  }

  onPaymentRequested(): void {
    if (this.cartService.isEmpty()) return;
    this.showPayment.set(true);
  }

  onPaymentComplete(result: any): void {
    this.showPayment.set(false);
    // Normalize: result could be { invoice, payments } or flat invoice object
    const invoice = result?.invoice || result;
    const payments = result?.payments || invoice?.payments || [];
    const invoiceNumber = invoice?.invoice_number || result?.invoice_number || '';

    // Generate and auto-print receipt
    const html = this.receiptService.generateReceipt(
      invoice,
      payments,
      this.session(),
      this.session()?.terminal
    );
    this.lastReceiptHtml.set(html);
    this.receiptService.printReceipt(html);
    this.cartService.clear();
    this.message.add({
      severity: 'success',
      summary: this.translate.instant('POS.SALE_COMPLETE'),
      detail: invoiceNumber ? `#${invoiceNumber}` : '',
      life: 3000,
    });
    this.loadProducts(); // refresh stock
  }

  onHoldOrder(): void {
    if (this.cartService.isEmpty()) return;
    const payload = this.cartService.toHeldOrderPayload();
    this.heldOrderService.holdOrder({
      ...payload,
      session_id: this.session()?.id,
    }).subscribe({
      next: () => {
        this.cartService.clear();
        this.message.add({
          severity: 'info',
          summary: this.translate.instant('POS.ORDER_HELD'),
          life: 2000,
        });
      },
    });
  }

  onRestoreOrder(order: HeldOrder): void {
    this.cartService.restoreFromHeldOrder(order);
    this.showHeldOrders.set(false);
  }

  onCloseSession(): void {
    this.showSessionClose.set(true);
  }

  onSessionClosed(): void {
    this.showSessionClose.set(false);
    this.session.set(null);
    this.offlineService.clearSession().catch(() => {});
    this.offlineService.clearSavedCart();
    this.router.navigate(['/dashboard']);
  }

  onExitRequested(): void {
    if (!this.cartService.isEmpty()) {
      this.confirm.confirm({
        message: this.translate.instant('POS.EXIT_CONFIRM'),
        header: this.translate.instant('POS.EXIT'),
        icon: 'pi pi-exclamation-triangle',
        accept: () => this.router.navigate(['/dashboard']),
      });
    } else {
      this.router.navigate(['/dashboard']);
    }
  }

  onCategoryChanged(categoryId: number | null): void {
    this.selectedCategory.set(categoryId);
    // Reload products for the selected category (server-side filter)
    this.loadProducts();
  }

  toggleLayout(): void {
    const order: ('cashier' | 'modern' | 'classic' | 'retail')[] = [
      'cashier',
      'modern',
      'classic',
      'retail',
    ];
    const idx = order.indexOf(this.posLayout());
    const next = order[(idx + 1) % order.length];
    this.posLayout.set(next);
    localStorage.setItem('pos_layout', next);
  }

  onPayCash(): void {
    if (this.cartService.isEmpty()) return;
    this.cashAmountPaid.set(this.cartService.total());
    this.cashChange.set(0);
    this.showQuickCash.set(true);
  }

  onCashAmountChange(amount: number): void {
    this.cashAmountPaid.set(amount || 0);
    this.cashChange.set(Math.max(0, (amount || 0) - this.cartService.total()));
  }

  confirmCashPayment(): void {
    this.showQuickCash.set(false);
    const invoiceData = this.cartService.toInvoicePayload(this.session()?.warehouse?.id);
    const paymentLines = [{ method: 'cash' as const, amount: this.cartService.total() }];
    this.processPayment(invoiceData, paymentLines);
  }

  onPayCard(): void {
    if (this.cartService.isEmpty()) return;
    const invoiceData = this.cartService.toInvoicePayload(this.session()?.warehouse?.id);
    const paymentLines = [{ method: 'credit_card' as const, amount: this.cartService.total() }];
    this.processPayment(invoiceData, paymentLines);
  }

  private processPayment(
    invoiceData: any,
    paymentLines: { method: string; amount: number; reference?: string }[]
  ): void {
    const fullInvoiceData = { ...invoiceData, session_id: this.session()?.id };

    // If offline or browser says no internet, queue immediately
    if (!navigator.onLine || this.offlineService.connectionStatus() === 'offline') {
      this.enqueueOfflineSale(fullInvoiceData, paymentLines);
      return;
    }

    // Show loading
    this.paymentProcessing.set(true);

    // Get receiving_account_id from terminal config
    const terminalId = this.session()?.terminal?.id;
    const receivingAccountId = terminalId ? this.getTerminalReceivingAccount(terminalId) : undefined;

    // Try online
    this.posService.processSale(fullInvoiceData, paymentLines, receivingAccountId).subscribe({
      next: (result) => {
        this.paymentProcessing.set(false);
        this.onPaymentComplete(result);
      },
      error: (err) => {
        this.paymentProcessing.set(false);
        const isNetworkError =
          !navigator.onLine ||
          err.status === 0 ||
          err.status === 504 ||
          err.status === 503 ||
          err.status === 502 ||
          err.statusText === 'Unknown Error' ||
          err.name === 'HttpErrorResponse' && !err.ok && err.status === 0;

        if (isNetworkError) {
          // Network error → queue for later sync
          this.offlineService.connectionStatus.set('offline');
          this.enqueueOfflineSale(fullInvoiceData, paymentLines);
        } else {
          // Real API error (validation, etc.)
          this.message.add({
            severity: 'error',
            summary: this.translate.instant('COMMON.ERROR'),
            detail: err?.error?.message || 'Payment failed',
            life: 3000,
          });
        }
      },
    });
  }

  private enqueueOfflineSale(
    invoiceData: any,
    paymentLines: { method: string; amount: number; reference?: string }[]
  ): void {
    const localId = crypto.randomUUID();
    this.offlineService.enqueue({
      type: 'sale',
      payload: { invoiceData, paymentLines },
      created_at: new Date().toISOString(),
      retries: 0,
      local_id: localId,
    }).then(() => {
      this.cartService.clear();
      this.offlineService.clearSavedCart();
      this.message.add({
        severity: 'warn',
        summary: this.translate.instant('POS.SALE_QUEUED'),
        detail: this.translate.instant('POS.SALE_QUEUED_DETAIL'),
        life: 5000,
      });
    });
  }

  onManualSync(): void {
    if (this.offlineService.isSyncing()) return;
    if (!navigator.onLine) {
      this.message.add({
        severity: 'warn',
        summary: this.translate.instant('POS.OFFLINE'),
        detail: this.translate.instant('POS.SYNC_OFFLINE_MSG'),
        life: 3000,
      });
      return;
    }
    this.offlineService.processQueue().then(() => {
      const remaining = this.offlineService.pendingCount();
      if (remaining === 0) {
        this.message.add({
          severity: 'success',
          summary: this.translate.instant('POS.SYNC_COMPLETE'),
          life: 3000,
        });
        this.loadProducts(); // refresh stock after sync
      } else {
        this.message.add({
          severity: 'warn',
          summary: this.translate.instant('POS.SYNC_PARTIAL'),
          detail: `${remaining} ${this.translate.instant('POS.PENDING')}`,
          life: 3000,
        });
      }
    });
  }

  onPrintLastReceipt(): void {
    const html = this.lastReceiptHtml();
    if (html) {
      this.receiptService.printReceipt(html);
    }
  }

  toggleOnScreenKeyboardSetting(): void {
    const newVal = !this.onScreenKeyboardEnabled();
    this.onScreenKeyboardEnabled.set(newVal);
    localStorage.setItem('pos_onscreen_keyboard', String(newVal));
    if (!newVal) {
      this.showOnScreenKeyboard.set(false);
    }
  }

  toggleOnScreenKeyboard(): void {
    if (!this.onScreenKeyboardEnabled()) return;
    this.showOnScreenKeyboard.update((v) => !v);
  }

  onKeyboardChar(char: string): void {
    const el = this.getActiveKeyboardTarget();
    if (el) {
      el.focus();
      el.value = el.value + char;
      el.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }

  onKeyboardBackspace(): void {
    const el = this.getActiveKeyboardTarget();
    if (el) {
      el.focus();
      el.value = el.value.slice(0, -1);
      el.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }

  onKeyboardEnter(): void {
    const el = this.getActiveKeyboardTarget();
    if (el) {
      el.focus();
      el.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
    }
  }

  onKeyboardClear(): void {
    const el = this.getActiveKeyboardTarget();
    if (el) {
      el.focus();
      el.value = '';
      el.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }

  /** Find the best input target: customer search > product search > barcode */
  private getActiveKeyboardTarget(): HTMLInputElement | null {
    return (
      document.querySelector('.cust-search-input') ||
      document.querySelector('.cust-form-input:focus') ||
      document.querySelector('.search-overlay-input') ||
      document.querySelector('.barcode-input')
    ) as HTMLInputElement | null;
  }

  private getTerminalReceivingAccount(terminalId: number): number | undefined {
    try {
      const map = JSON.parse(localStorage.getItem('pos_terminal_accounts') || '{}');
      return map[terminalId] || undefined;
    } catch { return undefined; }
  }
}
