import { Component, computed, inject, OnInit, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DialogModule } from 'primeng/dialog';
import { SelectModule } from 'primeng/select';
import { InputNumberModule } from 'primeng/inputnumber';
import { InputTextModule } from 'primeng/inputtext';
import { ButtonModule } from 'primeng/button';
import { ToastModule } from 'primeng/toast';
import { MessageService } from 'primeng/api';
import { input, output } from '@angular/core';
import { PosCartService } from '../../services/pos-cart.service';
import { PosService } from '../../services/pos.service';
import { PosOfflineService } from '../../services/pos-offline.service';
import { PosSession, PaymentLine, PaymentMethod } from '../../models/pos.model';

@Component({
  selector: 'app-payment-dialog',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    TranslateModule,
    DialogModule,
    SelectModule,
    InputNumberModule,
    InputTextModule,
    ButtonModule,
    ToastModule,
  ],
  providers: [MessageService],
  templateUrl: './payment-dialog.component.html',
  styleUrl: './payment-dialog.component.scss',
})
export class PaymentDialogComponent implements OnInit {
  readonly cartService = inject(PosCartService);
  private readonly posService = inject(PosService);
  private readonly offlineService = inject(PosOfflineService);
  private readonly message = inject(MessageService);
  private readonly translate = inject(TranslateService);
  readonly errorMsg = signal('');

  readonly session = input.required<PosSession>();
  readonly currencySymbol = input('');
  readonly paymentComplete = output<any>();
  readonly cancelled = output<void>();

  paymentMethods: { label: string; value: PaymentMethod }[] = [];

  readonly paymentLines = signal<PaymentLine[]>([
    { method: 'cash', amount: 0, reference: '' },
  ]);
  readonly loading = signal(false);

  readonly totalPaid = computed(() =>
    this.paymentLines().reduce((sum, line) => sum + (line.amount || 0), 0)
  );

  readonly remaining = computed(() =>
    Math.max(0, this.cartService.total() - this.totalPaid())
  );

  readonly change = computed(() =>
    Math.max(0, this.totalPaid() - this.cartService.total())
  );

  ngOnInit(): void {
    this.paymentMethods = [
      { label: this.translate.instant('POS.METHOD_CASH'), value: 'cash' },
      { label: this.translate.instant('POS.METHOD_CARD'), value: 'credit_card' },
      { label: this.translate.instant('POS.METHOD_TRANSFER'), value: 'bank_transfer' },
      { label: this.translate.instant('POS.METHOD_CHECK'), value: 'check' },
    ];
    this.paymentLines.set([
      { method: 'cash', amount: this.cartService.total(), reference: '' },
    ]);
  }

  updateLine(index: number, field: keyof PaymentLine, value: any): void {
    const lines = [...this.paymentLines()];
    lines[index] = { ...lines[index], [field]: value };
    this.paymentLines.set(lines);
  }

  addLine(): void {
    this.paymentLines.update((lines) => [
      ...lines,
      { method: 'cash', amount: 0, reference: '' },
    ]);
  }

  removeLine(index: number): void {
    this.paymentLines.update((lines) => lines.filter((_, i) => i !== index));
  }

  pay(): void {
    this.loading.set(true);
    this.errorMsg.set('');
    const warehouseId = this.session()?.warehouse?.id || 1;

    // Ensure customer_id — use walk-in if not set
    if (!this.cartService.customerId()) {
      this.cartService.setCustomer(5, 'عميل نقدي');
    }

    const invoicePayload = this.cartService.toInvoicePayload(warehouseId);
    const lines = this.paymentLines().map((line) => ({
      method: line.method,
      amount: line.amount,
      reference: line.reference || undefined,
    }));

    // If offline, queue and close
    if (!navigator.onLine || this.offlineService.connectionStatus() === 'offline') {
      this.enqueueAndClose(invoicePayload, lines);
      return;
    }

    this.posService.processSale(invoicePayload, lines).subscribe({
      next: (result) => {
        this.loading.set(false);
        this.paymentComplete.emit({
          ...result.invoice,
          invoice_number: result.invoice?.invoice_number,
          payments: result.payments,
          change: this.change(),
        });
      },
      error: (err) => {
        this.loading.set(false);
        const isNetworkError = !navigator.onLine || err.status === 0 || err.status >= 502 || err.statusText === 'Unknown Error';
        if (isNetworkError) {
          this.enqueueAndClose(invoicePayload, lines);
        } else {
          const errData = err.error;
          let msg = errData?.message || 'Sale failed';
          if (errData?.errors) {
            const allErrors = Object.values(errData.errors).flat();
            msg = allErrors.join('\n');
          }
          this.errorMsg.set(msg);
          this.message.add({ severity: 'error', summary: this.translate.instant('COMMON.ERROR'), detail: msg, life: 8000 });
        }
      },
    });
  }

  private async enqueueAndClose(invoicePayload: any, lines: any[]): Promise<void> {
    try {
      const localId = crypto.randomUUID();
      await this.offlineService.enqueue({
        type: 'sale',
        payload: { invoiceData: invoicePayload, paymentLines: lines },
        created_at: new Date().toISOString(),
        retries: 0,
        local_id: localId,
      });

      this.loading.set(false);
      this.message.add({
        severity: 'warn',
        summary: this.translate.instant('POS.SALE_QUEUED'),
        detail: this.translate.instant('POS.SALE_QUEUED_DETAIL'),
        life: 5000,
      });

      this.paymentComplete.emit({
        offline: true,
        local_id: localId,
        change: this.change(),
      });
    } catch (e) {
      this.loading.set(false);
      this.errorMsg.set('Failed to queue offline sale');
    }
  }
}
