import {
  Component,
  input,
  output,
  signal,
  computed,
  effect,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { AppCardComponent } from '../../../../shared/components/app-card/app-card.component';
import { AppButtonComponent } from '../../../../shared/components/app-button/app-button.component';
import { SummaryCardComponent } from '../../../../shared/components/summary-card/summary-card.component';
import {
  PriceBreakdownComponent,
  PriceBreakdownRow,
} from '../../../../shared/components/price-breakdown/price-breakdown.component';
import { QuoteResult, QuoteItem } from '../../services/quote-estimator.service';

@Component({
  selector: 'app-quote-result',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    TranslateModule,
    AppCardComponent,
    AppButtonComponent,
    SummaryCardComponent,
    PriceBreakdownComponent,
  ],
  templateUrl: './quote-result.component.html',
  styleUrl: './quote-result.component.scss',
})
export class QuoteResultComponent {
  readonly maxInputQuantity = 500;
  readonly directOrderLimit = 100;

  result = input.required<QuoteResult>();
  recalculationRequired = input<boolean>(false);
  itemSettingsDiffByFileName = input<Record<string, { differences: string[] }>>(
    {},
  );
  consult = output<void>();
  proceed = output<void>();
  itemChange = output<{
    id?: string;
    index: number;
    fileName: string;
    quantity: number;
  }>();
  itemQuantityPreviewChange = output<{
    id?: string;
    index: number;
    fileName: string;
    quantity: number;
  }>();

  // Local mutable state for items to handle quantity changes
  items = signal<QuoteItem[]>([]);
  private lastSentQuantities = new Map<string, number>();

  constructor() {
    effect(
      () => {
        // Initialize local items when result inputs change
        // We map to new objects to avoid mutating the input directly if it was a reference
        const nextItems = this.result().items.map((i) => ({ ...i }));
        this.items.set(nextItems);

        this.lastSentQuantities.clear();
        nextItems.forEach((item) => {
          const key = item.id ?? item.fileName;
          this.lastSentQuantities.set(key, item.quantity);
        });
      },
      { allowSignalWrites: true },
    );
  }

  updateQuantity(index: number, newQty: number | string) {
    const normalizedQty = this.normalizeQuantity(newQty);
    if (normalizedQty === null) return;

    const item = this.items()[index];
    if (!item) return;

    this.items.update((current) => {
      const updated = [...current];
      updated[index] = { ...updated[index], quantity: normalizedQty };
      return updated;
    });

    this.itemQuantityPreviewChange.emit({
      id: item.id,
      index,
      fileName: item.fileName,
      quantity: normalizedQty,
    });
  }

  flushQuantityUpdate(index: number): void {
    const item = this.items()[index];
    if (!item) return;

    const key = item.id ?? item.fileName;

    const normalizedQty = this.normalizeQuantity(item.quantity);
    if (normalizedQty === null) return;

    if (this.lastSentQuantities.get(key) === normalizedQty) {
      return;
    }

    this.itemChange.emit({
      id: item.id,
      index,
      fileName: item.fileName,
      quantity: normalizedQty,
    });
    this.lastSentQuantities.set(key, normalizedQty);
  }

  hasQuantityOverLimit = computed(() =>
    this.items().some((item) => item.quantity > this.directOrderLimit),
  );

  costBreakdown = computed(() => {
    const currentItems = this.items();
    const cad = this.result().cadTotal || 0;

    let subtotal = cad;
    currentItems.forEach((item) => {
      subtotal += item.unitPrice * item.quantity;
    });

    const nozzleChange = Math.max(0, this.result().nozzleChangeCost || 0);
    const baseSetupRaw =
      this.result().baseSetupCost != null
        ? this.result().baseSetupCost
        : this.result().setupCost - nozzleChange;
    const baseSetup = Math.max(0, baseSetupRaw || 0);
    const total = subtotal + baseSetup + nozzleChange;

    return {
      subtotal: Math.round(subtotal * 100) / 100,
      baseSetup: Math.round(baseSetup * 100) / 100,
      nozzleChange: Math.round(nozzleChange * 100) / 100,
      total: Math.round(total * 100) / 100,
    };
  });

  priceBreakdownRows = computed<PriceBreakdownRow[]>(() => {
    const breakdown = this.costBreakdown();

    return [
      {
        labelKey: 'CHECKOUT.SUBTOTAL',
        amount: breakdown.subtotal,
      },
      {
        labelKey: 'CHECKOUT.SETUP_FEE',
        amount: breakdown.baseSetup,
      },
      {
        label: 'Cambio Ugello',
        amount: breakdown.nozzleChange,
        visible: breakdown.nozzleChange > 0,
      },
    ];
  });

  totals = computed(() => {
    const currentItems = this.items();
    let time = 0;
    let weight = 0;

    currentItems.forEach((i) => {
      time += i.unitTime * i.quantity;
      weight += i.unitWeight * i.quantity;
    });

    const hours = Math.floor(time / 3600);
    const minutes = Math.ceil((time % 3600) / 60);

    return {
      price: this.costBreakdown().total,
      hours,
      minutes,
      weight: Math.ceil(weight),
    };
  });

  private normalizeQuantity(newQty: number | string): number | null {
    const qty = typeof newQty === 'string' ? parseInt(newQty, 10) : newQty;
    if (!Number.isFinite(qty) || qty < 1) {
      return null;
    }
    return Math.min(qty, this.maxInputQuantity);
  }

  getItemDifferenceLabel(fileName: string, materialCode?: string): string {
    const differences =
      this.itemSettingsDiffByFileName()[fileName]?.differences || [];
    if (differences.length === 0) return '';

    const normalizedMaterial = String(materialCode || '')
      .trim()
      .toLowerCase();

    const filtered = differences.filter((entry) => {
      const normalized = String(entry || '')
        .trim()
        .toLowerCase();
      const isMaterialOnly = !normalized.includes(':');
      return !(isMaterialOnly && normalized === normalizedMaterial);
    });

    if (filtered.length === 0) {
      return '';
    }

    const materialOnly = filtered.find(
      (entry) => !entry.includes(':') && entry.trim().length > 0,
    );
    return materialOnly || filtered.join(' | ');
  }
}
