import { Component, inject, OnInit, OnDestroy, signal, ViewChild, ElementRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormGroup, FormArray, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { Subject, firstValueFrom } from 'rxjs';
import { debounceTime, switchMap, filter, distinctUntilChanged } from 'rxjs/operators';
import { TableModule } from 'primeng/table';
import { ButtonModule } from 'primeng/button';
import { InputTextModule } from 'primeng/inputtext';
import { InputNumberModule } from 'primeng/inputnumber';
import { SelectModule } from 'primeng/select';
import { DatePickerModule } from 'primeng/datepicker';
import { TagModule } from 'primeng/tag';
import { ToastModule } from 'primeng/toast';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { TextareaModule } from 'primeng/textarea';
import { TooltipModule } from 'primeng/tooltip';
import { DialogModule } from 'primeng/dialog';
import { MessageService, ConfirmationService } from 'primeng/api';
import { PageHeaderComponent, DataTableComponent, FormDialogComponent, TableColumn } from '../../shared';
import { InventoryTransferService } from '../../core/services/inventory-transfer.service';
import { ProductService } from '../../core/services/product.service';
import { SettingService } from '../../core/services/setting.service';
import { InventoryTransfer, StockBalance } from '../../core/models/inventory.model';
import { StockBalanceService } from '../../core/services/stock-balance.service';
import { Product, ProductVariant } from '../../core/models/product.model';
import { selectAllUnits, UnitsActions } from '../../core/store';
import { WarehouseService } from '../../core/services/warehouse.service';
import { Warehouse } from '../../core/models/warehouse.model';

interface ReceiveItem {
  transfer_item_id: number;
  product_name: string;
  requested_quantity: number;
  received_quantity: number;
}

@Component({
  selector: 'app-warehouse-transfers',
  standalone: true,
  imports: [
    CommonModule, FormsModule, ReactiveFormsModule, TranslateModule,
    TableModule, ButtonModule, InputTextModule, InputNumberModule,
    SelectModule, DatePickerModule, TagModule, ToastModule,
    ConfirmDialogModule, TextareaModule, TooltipModule, DialogModule,
    PageHeaderComponent, DataTableComponent, FormDialogComponent,
  ],
  providers: [MessageService, ConfirmationService],
  templateUrl: './warehouse-transfers.component.html',
  styleUrl: './warehouse-transfers.component.scss',
})
export class WarehouseTransfersComponent implements OnInit, OnDestroy {
  readonly columns: TableColumn[] = [
    { field: 'transfer_number', header: 'INVENTORY.TRANSFER_NUMBER' },
    { field: 'date', header: 'INVENTORY.DATE' },
    { field: 'from_warehouse', header: 'INVENTORY.FROM_WAREHOUSE' },
    { field: 'to_warehouse', header: 'INVENTORY.TO_WAREHOUSE' },
    { field: 'total_quantity', header: 'INVENTORY.TOTAL_QUANTITY' },
    { field: 'status', header: 'COMMON.STATUS' },
    { field: 'actions', header: 'COMMON.ACTIONS' },
  ];

  private fb = inject(FormBuilder);
  private store = inject(Store);
  private messageService = inject(MessageService);
  private confirmationService = inject(ConfirmationService);
  private translate = inject(TranslateService);
  private inventoryTransferService = inject(InventoryTransferService);
  private productService = inject(ProductService);
  private settingService = inject(SettingService);
  private warehouseService = inject(WarehouseService);
  private stockBalanceService = inject(StockBalanceService);

  units$ = this.store.select(selectAllUnits);

  stockQtyMap = signal<Record<string, number>>({});
  searchedProducts = signal<Product[]>([]);
  minSearchChars = signal(3);
  searchLoading = signal(false);
  private searchSubject = new Subject<string>();

  products = signal<Product[]>([]);
  productVariantsMap = signal<Record<number, ProductVariant[]>>({});

  items = signal<InventoryTransfer[]>([]);
  loading = signal(false);
  saving = signal(false);
  dialogVisible = signal(false);
  editing = signal<InventoryTransfer | null>(null);
  detailDialogVisible = signal(false);
  selectedTransfer = signal<InventoryTransfer | null>(null);
  receiveDialogVisible = signal(false);
  receivingTransfer = signal<InventoryTransfer | null>(null);
  receiveItems = signal<ReceiveItem[]>([]);
  warehouses = signal<Warehouse[]>([]);

  form!: FormGroup;

  ngOnInit(): void {
    this.form = this.fb.group({
      from_warehouse_id: [null, Validators.required],
      to_warehouse_id: [null, Validators.required],
      date: [new Date(), Validators.required],
      notes: [''],
      items: this.fb.array([]),
    });

    this.store.dispatch(UnitsActions.loadUnits({}));

    // Server-side product search pipeline
    this.searchSubject.pipe(
      debounceTime(300),
      filter(q => q.length >= this.minSearchChars()),
      switchMap(q => {
        this.searchLoading.set(true);
        return this.productService.searchForDropdown(q);
      }),
    ).subscribe({
      next: (res) => {
        this.searchedProducts.set(res.data);
        this.products.set(res.data);
        this.searchLoading.set(false);
      },
      error: () => this.searchLoading.set(false),
    });

    // Load min search chars from settings
    this.settingService.getByKey('products.min_search_chars').subscribe({
      next: (res: any) => {
        const val = parseInt(res?.data?.value ?? res?.value, 10);
        if (!isNaN(val) && val > 0) this.minSearchChars.set(val);
      },
      error: () => {},
    });

    this.warehouseService.listForCurrentBranch().subscribe({
      next: (res) => this.warehouses.set(res.data),
      error: () => {},
    });

    this.loadData();
  }

  get itemsArray(): FormArray {
    return this.form.get('items') as FormArray;
  }

  loadData(): void {
    this.loading.set(true);
    this.inventoryTransferService.listAll().subscribe({
      next: (res) => { this.items.set(res.data); this.loading.set(false); },
      error: (err) => { this.loading.set(false); this.showError(err); },
    });
  }

  openNew(): void {
    this.editing.set(null);
    this.form.reset({ date: new Date() });
    this.itemsArray.clear();
    this.searchedProducts.set([]);
    this.products.set([]);
    this.addItem();
    this.dialogVisible.set(true);
  }

  edit(item: InventoryTransfer): void {
    this.editing.set(item);
    this.form.patchValue({
      from_warehouse_id: item.from_warehouse_id,
      to_warehouse_id: item.to_warehouse_id,
      date: new Date(item.date),
      notes: item.notes,
    });
    this.itemsArray.clear();
    // Pre-load existing line products into searchedProducts for dropdown display
    if (item.items && item.items.length > 0) {
      const existingProducts: Product[] = item.items
        .filter(line => line.product_id)
        .map(line => ({
          id: line.product_id,
          name_ar: line.product?.name || '',
          name_en: line.product?.name || '',
          code: line.product?.code || '',
          category: (line.product as any)?.category || null,
        } as any as Product));
      this.searchedProducts.set(existingProducts);
      this.products.set(existingProducts);

      item.items.forEach(line => {
        this.itemsArray.push(this.fb.group({
          product_id: [line.product_id, Validators.required],
          product_variant_id: [line.product_variant_id],
          unit_id: [line.unit_id, Validators.required],
          requested_quantity: [line.requested_quantity, [Validators.required, Validators.min(0.01)]],
        }));
        if (line.product_variant_id) {
          this.onProductChange(this.itemsArray.length - 1, line.product_id);
        }
      });
    } else {
      this.addItem();
    }
    this.dialogVisible.set(true);
  }

  onSave(): void {
    if (this.form.valid && this.itemsArray.length > 0) {
      this.saving.set(true);
      const val = this.form.value;
      const data = {
        from_warehouse_id: val.from_warehouse_id,
        to_warehouse_id: val.to_warehouse_id,
        date: this.formatDate(val.date),
        notes: val.notes || null,
        items: val.items.map((item: any) => ({
          product_id: item.product_id,
          product_variant_id: item.product_variant_id || null,
          unit_id: item.unit_id,
          requested_quantity: item.requested_quantity,
        })),
      };
      const obs = this.editing()
        ? this.inventoryTransferService.update(this.editing()!.id, data)
        : this.inventoryTransferService.create(data);
      obs.subscribe({
        next: () => {
          this.saving.set(false);
          this.dialogVisible.set(false);
          this.messageService.add({
            severity: 'success',
            summary: this.translate.instant('COMMON.SUCCESS'),
            detail: this.translate.instant(this.editing() ? 'INVENTORY.TRANSFER_UPDATE_SUCCESS' : 'INVENTORY.TRANSFER_CREATE_SUCCESS'),
          });
          this.loadData();
        },
        error: (err) => { this.saving.set(false); this.showError(err); },
      });
    } else {
      this.form.markAllAsTouched();
    }
  }

  delete(item: InventoryTransfer): void {
    this.confirmationService.confirm({
      message: this.translate.instant('INVENTORY.CONFIRM_DELETE_TRANSFER'),
      header: this.translate.instant('COMMON.CONFIRM'),
      icon: 'pi pi-exclamation-triangle',
      acceptButtonStyleClass: 'p-button-danger',
      accept: () => {
        this.saving.set(true);
        this.inventoryTransferService.delete(item.id).subscribe({
          next: () => {
            this.saving.set(false);
            this.items.update(items => items.filter(i => i.id !== item.id));
            this.messageService.add({
              severity: 'success',
              summary: this.translate.instant('COMMON.SUCCESS'),
              detail: this.translate.instant('INVENTORY.TRANSFER_DELETE_SUCCESS'),
            });
          },
          error: (err) => { this.saving.set(false); this.showError(err); },
        });
      },
    });
  }

  ship(item: InventoryTransfer): void {
    this.confirmationService.confirm({
      message: this.translate.instant('INVENTORY.CONFIRM_SHIP_TRANSFER'),
      header: this.translate.instant('COMMON.CONFIRM'),
      icon: 'pi pi-truck',
      accept: () => {
        this.saving.set(true);
        this.inventoryTransferService.ship(item.id).subscribe({
          next: (res) => {
            this.saving.set(false);
            this.items.update(items => items.map(i => i.id === res.data.id ? res.data : i));
            this.messageService.add({
              severity: 'success',
              summary: this.translate.instant('COMMON.SUCCESS'),
              detail: this.translate.instant('INVENTORY.TRANSFER_SHIP_SUCCESS'),
            });
          },
          error: (err) => { this.saving.set(false); this.showError(err); },
        });
      },
    });
  }

  openReceiveDialog(item: InventoryTransfer): void {
    this.inventoryTransferService.getById(item.id).subscribe({
      next: (res) => {
        const transfer = res.data;
        this.receivingTransfer.set(transfer);
        this.receiveItems.set(
          transfer.items.map(line => ({
            transfer_item_id: line.id,
            product_name: (line.product?.name || '') + (line.product_variant ? ' - ' + line.product_variant.name : ''),
            requested_quantity: line.requested_quantity,
            received_quantity: line.shipped_quantity || line.requested_quantity,
          }))
        );
        this.receiveDialogVisible.set(true);
      },
      error: (err) => this.showError(err),
    });
  }

  updateReceivedQuantity(index: number, value: number): void {
    this.receiveItems.update(items => {
      const updated = [...items];
      updated[index] = { ...updated[index], received_quantity: value };
      return updated;
    });
  }

  onReceive(): void {
    const transfer = this.receivingTransfer();
    if (!transfer) return;

    this.saving.set(true);
    const data = {
      items: this.receiveItems().map(item => ({
        transfer_item_id: item.transfer_item_id,
        received_quantity: item.received_quantity,
      })),
    };
    this.inventoryTransferService.receive(transfer.id, data).subscribe({
      next: (res) => {
        this.saving.set(false);
        this.receiveDialogVisible.set(false);
        this.items.update(items => items.map(i => i.id === res.data.id ? res.data : i));
        this.messageService.add({
          severity: 'success',
          summary: this.translate.instant('COMMON.SUCCESS'),
          detail: this.translate.instant('INVENTORY.TRANSFER_RECEIVE_SUCCESS'),
        });
      },
      error: (err) => { this.saving.set(false); this.showError(err); },
    });
  }

  cancel(item: InventoryTransfer): void {
    this.confirmationService.confirm({
      message: this.translate.instant('INVENTORY.CONFIRM_CANCEL_TRANSFER'),
      header: this.translate.instant('COMMON.CONFIRM'),
      icon: 'pi pi-exclamation-triangle',
      acceptButtonStyleClass: 'p-button-danger',
      accept: () => {
        this.saving.set(true);
        this.inventoryTransferService.cancel(item.id).subscribe({
          next: (res) => {
            this.saving.set(false);
            this.items.update(items => items.map(i => i.id === res.data.id ? res.data : i));
            this.messageService.add({
              severity: 'success',
              summary: this.translate.instant('COMMON.SUCCESS'),
              detail: this.translate.instant('INVENTORY.TRANSFER_CANCEL_SUCCESS'),
            });
          },
          error: (err) => { this.saving.set(false); this.showError(err); },
        });
      },
    });
  }

  viewDetail(item: InventoryTransfer): void {
    this.inventoryTransferService.getById(item.id).subscribe({
      next: (res) => {
        this.selectedTransfer.set(res.data);
        this.detailDialogVisible.set(true);
      },
      error: (err) => this.showError(err),
    });
  }

  addItem(): void {
    this.itemsArray.push(this.fb.group({
      product_id: [null, Validators.required],
      product_variant_id: [null],
      unit_id: [null, Validators.required],
      requested_quantity: [1, [Validators.required, Validators.min(0.01)]],
    }));
  }

  ngOnDestroy(): void {
    this.searchSubject.complete();
  }

  onProductSearch(event: { filter: string }): void {
    const q = event.filter?.trim() || '';
    if (q.length < this.minSearchChars()) {
      this.searchedProducts.set([]);
      return;
    }
    this.searchSubject.next(q);
  }

  onProductChange(index: number, productId: number): void {
    const product = this.products().find(p => p.id === productId);
    if (product?.has_variants && !this.productVariantsMap()[productId]) {
      this.productService.listVariants(productId).subscribe({
        next: (res) => {
          this.productVariantsMap.update(m => ({ ...m, [productId]: res.data }));
        },
      });
    }
    const group = this.itemsArray.at(index) as FormGroup;
    group.patchValue({ product_variant_id: null });
    if (product?.base_unit_id) {
      group.patchValue({ unit_id: product.base_unit_id });
    } else if (product) {
      this.productService.listProductUnits(product.id).subscribe({
        next: (res) => {
          const firstUnit = res.data?.[0]?.unit_id || null;
          if (firstUnit) group.patchValue({ unit_id: firstUnit });
        },
      });
    }
    this.loadStockForProduct(productId);
  }

  private loadStockForProduct(productId: number): void {
    const warehouseId = this.form.get('from_warehouse_id')?.value;
    const filters: any = { product_id: productId };
    if (warehouseId) filters.warehouse_id = warehouseId;
    this.stockBalanceService.listFiltered(filters).subscribe({
      next: (res) => {
        this.stockQtyMap.update(m => {
          const updated = { ...m };
          let total = 0;
          res.data.forEach(b => {
            const key = b.product_variant_id ? `${productId}-${b.product_variant_id}` : `${productId}`;
            updated[key] = +b.available_quantity || 0;
            total += +b.available_quantity || 0;
          });
          updated[`${productId}`] = total;
          return updated;
        });
      },
    });
  }

  getStockQty(productId: number, variantId: number | null): number | null {
    if (!productId) return null;
    const key = variantId ? `${productId}-${variantId}` : `${productId}`;
    return this.stockQtyMap()[key] ?? null;
  }

  getProductVariants(productId: number): ProductVariant[] {
    return this.productVariantsMap()[productId] || [];
  }

  isVariantProduct(productId: number): boolean {
    const product = this.products().find(p => p.id === productId);
    return !!product?.has_variants;
  }

  removeItem(index: number): void {
    this.itemsArray.removeAt(index);
  }

  @ViewChild('barcodeInput') barcodeInput!: ElementRef<HTMLInputElement>;
  barcodeValue = signal('');
  barcodeLoading = signal(false);

  onBarcodeScan(event: Event): void {
    event.preventDefault();
    const barcode = this.barcodeValue().trim();
    if (!barcode) return;

    this.barcodeLoading.set(true);
    this.productService.lookupByBarcode(barcode).subscribe({
      next: (result) => {
        this.barcodeLoading.set(false);
        if (result) {
          if (result.variants) {
            this.productVariantsMap.update(m => ({ ...m, [result.product.id]: result.variants! }));
          }
          this.addProductByBarcode(result.product, result.variantId);
        } else {
          this.messageService.add({
            severity: 'warn',
            summary: this.translate.instant('COMMON.WARNING'),
            detail: this.translate.instant('INVENTORY.BARCODE_NOT_FOUND'),
          });
          this.barcodeValue.set('');
          setTimeout(() => this.barcodeInput?.nativeElement?.focus(), 50);
        }
      },
      error: () => {
        this.barcodeLoading.set(false);
        this.messageService.add({ severity: 'error', summary: this.translate.instant('COMMON.ERROR'), detail: this.translate.instant('INVENTORY.BARCODE_SEARCH_FAILED') });
      },
    });
  }

  private addProductByBarcode(product: Product, variantId: number | null): void {
    const current = this.searchedProducts();
    if (!current.find(p => p.id === product.id)) {
      this.searchedProducts.set([...current, product]);
      this.products.set([...this.products(), product]);
    }

    // Check if product+variant already exists → increment quantity
    for (let i = 0; i < this.itemsArray.length; i++) {
      const row = this.itemsArray.at(i) as FormGroup;
      if (row.get('product_id')?.value === product.id &&
          (row.get('product_variant_id')?.value || null) === (variantId || null)) {
        const currentQty = row.get('requested_quantity')?.value || 0;
        row.patchValue({ requested_quantity: currentQty + 1 });
        this.barcodeValue.set('');
        setTimeout(() => this.barcodeInput?.nativeElement?.focus(), 50);
        return;
      }
    }

    const lastIndex = this.itemsArray.length - 1;
    const lastRow = lastIndex >= 0 ? this.itemsArray.at(lastIndex) as FormGroup : null;
    const useExistingRow = lastRow && !lastRow.get('product_id')?.value;

    const fillRow = (unitId: number | null) => {
      if (useExistingRow) {
        lastRow!.patchValue({
          product_id: product.id,
          product_variant_id: variantId,
          unit_id: unitId,
          requested_quantity: 1,
        });
      } else {
        this.itemsArray.push(this.fb.group({
          product_id: [product.id, Validators.required],
          product_variant_id: [variantId],
          unit_id: [unitId, Validators.required],
          requested_quantity: [1, [Validators.required, Validators.min(0.01)]],
        }));
      }
      this.barcodeValue.set('');
      setTimeout(() => this.barcodeInput?.nativeElement?.focus(), 50);
    };

    if (product.base_unit_id) {
      fillRow(product.base_unit_id);
    } else {
      this.productService.listProductUnits(product.id).subscribe({
        next: async (res) => {
          if (res.data?.length > 0) {
            fillRow(res.data[0].unit_id);
          } else {
            const units = await firstValueFrom(this.units$);
            fillRow(units?.[0]?.id || null);
          }
        },
        error: async () => {
          const units = await firstValueFrom(this.units$);
          fillRow(units?.[0]?.id || null);
        },
      });
    }
  }

  getStatusSeverity(status: string): 'success' | 'warn' | 'danger' | 'info' {
    switch (status) {
      case 'draft': return 'warn';
      case 'shipped': return 'info';
      case 'received': return 'success';
      case 'cancelled': return 'danger';
      default: return 'warn';
    }
  }

  private showError(err: any): void {
    const detail = err.error?.message || err.error?.errors
      ? (err.error.message || Object.values(err.error.errors || {}).flat().join(', '))
      : 'Failed';
    this.messageService.add({
      severity: 'error',
      summary: this.translate.instant('COMMON.ERROR'),
      detail,
    });
  }

  private formatDate(date: Date): string {
    const y = date.getFullYear();
    const m = String(date.getMonth() + 1).padStart(2, '0');
    const d = String(date.getDate()).padStart(2, '0');
    return `${y}-${m}-${d}`;
  }
}
