import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { TranslatePipe } from '../../../../../i18n/translate.pipe';
import { ButtonComponent } from '../../../../../shared/ui/button/button.component';
import { InputComponent } from '../../../../../shared/ui/input/input.component';
import { ImageFieldComponent } from '../../../../../shared/ui/image-field/image-field.component';
import { AdminProductVariant, AdminProductVariantAttributeDef, AdminProductVariantPrice } from '../../models/admin-product.model';

const DEFAULT_CURRENCIES = ['RUB', 'USD', 'EUR', 'AMD'];

/** '0x8B4513' (production shape) or '#8B4513' -> '#8b4513' for CSS/<input type=color>. */
export function toCssColor(value: string): string {
  const hex = value.trim().replace(/^0x/i, '#');
  return /^#[0-9a-f]{6}$/i.test(hex) ? hex.toLowerCase() : '#cccccc';
}

/** '#8b4513' -> '0x8B4513' to match the production payload shape on save. */
export function toBackendColor(value: string): string {
  return `0x${value.replace('#', '').toUpperCase()}`;
}

function attributeSignature(attributes: Record<string, string>): string {
  return Object.keys(attributes).sort().map(key => `${key}=${attributes[key]}`).join('|');
}

@Component({
  selector: 'app-product-variants-editor',
  standalone: true,
  imports: [CommonModule, FormsModule, TranslatePipe, ButtonComponent, InputComponent, ImageFieldComponent],
  templateUrl: './product-variants-editor.component.html',
  styleUrl: './product-variants-editor.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProductVariantsEditorComponent {
  @Input() attributes: AdminProductVariantAttributeDef[] = [];
  @Input() variants: AdminProductVariant[] = [];

  @Output() attributesChange = new EventEmitter<AdminProductVariantAttributeDef[]>();
  @Output() variantsChange = new EventEmitter<AdminProductVariant[]>();

  readonly defaultCurrencies = DEFAULT_CURRENCIES;
  readonly toCssColor = toCssColor;

  newAttributeName = '';
  newAttributeIsColor = false;
  newValueByAttribute: Record<string, string> = {};
  newColorByAttribute: Record<string, string> = {};

  addAttribute(): void {
    const label = this.newAttributeName.trim();
    if (!label) {
      return;
    }
    const key = label.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '') || `attr-${this.attributes.length + 1}`;
    if (this.attributes.some(attr => attr.key === key)) {
      return;
    }
    this.attributesChange.emit([...this.attributes, { key, label, isColor: this.newAttributeIsColor, values: [] }]);
    this.newAttributeName = '';
    this.newAttributeIsColor = false;
  }

  removeAttribute(key: string): void {
    this.attributesChange.emit(this.attributes.filter(attr => attr.key !== key));
    this.variantsChange.emit(this.variants.filter(variant => !(key in variant.attributes)));
  }

  addValue(attrKey: string): void {
    const attr = this.attributes.find(a => a.key === attrKey);
    if (!attr) {
      return;
    }
    const raw = attr.isColor ? this.newColorByAttribute[attrKey] : this.newValueByAttribute[attrKey];
    const value = attr.isColor ? (raw ? toBackendColor(raw) : '') : (raw ?? '').trim();
    if (!value || attr.values.includes(value)) {
      return;
    }
    this.attributesChange.emit(this.attributes.map(a => a.key === attrKey ? { ...a, values: [...a.values, value] } : a));
    this.newValueByAttribute[attrKey] = '';
  }

  removeValue(attrKey: string, value: string): void {
    this.attributesChange.emit(this.attributes.map(a => a.key === attrKey ? { ...a, values: a.values.filter(v => v !== value) } : a));
    this.variantsChange.emit(this.variants.filter(variant => variant.attributes[attrKey] !== value));
  }

  /** Cartesian product of all attribute values; keeps existing variant data (price/sku/stock) for combos that already exist. */
  generateVariants(): void {
    const withValues = this.attributes.filter(attr => attr.values.length > 0);
    if (withValues.length === 0) {
      return;
    }

    let combos: Record<string, string>[] = [{}];
    for (const attr of withValues) {
      const next: Record<string, string>[] = [];
      for (const combo of combos) {
        for (const value of attr.values) {
          next.push({ ...combo, [attr.key]: value });
        }
      }
      combos = next;
    }

    const existingBySignature = new Map(this.variants.map(v => [attributeSignature(v.attributes), v]));
    const generated = combos.map((attributes, index) => {
      const existing = existingBySignature.get(attributeSignature(attributes));
      return existing ?? {
        id: `variant-${Date.now()}-${index}`,
        attributes,
        sku: '',
        image: '',
        remaining: 0,
        prices: [],
      };
    });
    this.variantsChange.emit(generated);
  }

  attributeLabel(key: string): string {
    return this.attributes.find(attr => attr.key === key)?.label ?? key;
  }

  isColorAttribute(key: string): boolean {
    return !!this.attributes.find(attr => attr.key === key)?.isColor;
  }

  updateVariant(id: string, patch: Partial<AdminProductVariant>): void {
    this.variantsChange.emit(this.variants.map(v => v.id === id ? { ...v, ...patch } : v));
  }

  updateVariantSku(id: string, sku: string): void {
    this.updateVariant(id, { sku });
  }

  updateVariantRemaining(id: string, remaining: number): void {
    this.updateVariant(id, { remaining });
  }

  updateVariantImage(id: string, image: string): void {
    this.updateVariant(id, { image });
  }

  removeVariant(id: string): void {
    this.variantsChange.emit(this.variants.filter(v => v.id !== id));
  }

  addPrice(variant: AdminProductVariant, currency: string): void {
    if (!currency || variant.prices.some(p => p.currency === currency)) {
      return;
    }
    this.updateVariant(variant.id, { prices: [...variant.prices, { currency, price: 0 }] });
  }

  updatePrice(variant: AdminProductVariant, currency: string, price: number): void {
    this.updateVariant(variant.id, {
      prices: variant.prices.map((p): AdminProductVariantPrice => p.currency === currency ? { ...p, price } : p),
    });
  }

  removePrice(variant: AdminProductVariant, currency: string): void {
    this.updateVariant(variant.id, { prices: variant.prices.filter(p => p.currency !== currency) });
  }

  availableCurrencies(variant: AdminProductVariant): string[] {
    return this.defaultCurrencies.filter(currency => !variant.prices.some(p => p.currency === currency));
  }
}
