import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import {
  AbstractControl,
  FormArray,
  FormBuilder,
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  ValidationErrors,
  Validators
} from '@angular/forms';
import { forkJoin } from 'rxjs';

import { SidebarComponent } from '../../components/sidebar/sidebar.component';
import { AuthUser } from '../../models/auth-user.model';
import { Branch } from '../../models/branch.model';
import { Commission } from '../../models/commission.model';
import { Sale } from '../../models/sale.model';
import {
  CreateTicketResponse,
  ReceivableAccountSummary,
  ticket,
  TicketPaymentMethod
} from '../../models/Ticket.model';
import { User } from '../../models/user.model';
import { AuthService } from '../../services/auth.service';
import { BranchService } from '../../services/branch.service';
import { CommissionService } from '../../services/commission.service';
import { SaleService } from '../../services/sale.service';
import { TicketService } from '../../services/ticket.service';
import { UserService } from '../../services/user.service';
import { PageTopbarComponent } from '../../shared/components/page-topbar/page-topbar.component';

interface SaleLineView {
  productName: string;
  sellerName: string;
  volume: number;
  unitPrice: number;
  total: number;
}

@Component({
  selector: 'app-nueva-venta',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule, SidebarComponent, PageTopbarComponent],
  templateUrl: './nueva-venta.page.html',
  styleUrls: ['./nueva-venta.page.scss']
})
export class NuevaVentaPage implements OnInit {
  form: FormGroup;
  loading = true;
  submitting = false;
  errorMessage = '';
  successMessage = '';

  branches: Branch[] = [];
  saleCatalog: Sale[] = [];
  users: User[] = [];
  commissions: Commission[] = [];
  currentUser: AuthUser | null = null;
  createdResult: CreateTicketResponse | null = null;

  readonly paymentMethodOptions: { label: string; value: TicketPaymentMethod }[] = [
    { label: 'Efectivo', value: 'CASH' },
    { label: 'Transferencia', value: 'TRANSFER' },
    { label: 'Tarjeta', value: 'CARD' },
    { label: 'Credito', value: 'CREDIT' },
    { label: 'Otro', value: 'OTHER' }
  ];

  constructor(
    private fb: FormBuilder,
    private authService: AuthService,
    private branchService: BranchService,
    private saleService: SaleService,
    private userService: UserService,
    private commissionService: CommissionService,
    private ticketService: TicketService
  ) {
    this.form = this.fb.group(
      {
        branchId: [null, Validators.required],
        createdByUserId: [{ value: null, disabled: true }, Validators.required],
        folio: ['', [Validators.required, Validators.maxLength(80)]],
        invoiced: [false],
        uuid: [''],
        invoiceDate: [''],
        amountPaid: [0, [Validators.required, Validators.min(0)]],
        paymentMethod: ['CASH', Validators.required],
        dueDate: [''],
        paymentReference: [''],
        notes: [''],
        sales: this.fb.array([this.createSaleLineGroup()])
      },
      {
        validators: [this.creditDueDateValidator(), this.amountPaidValidator()]
      }
    );
  }

  ngOnInit(): void {
    this.loadInitialData();
    this.watchDynamicRules();
  }

  get salesFormArray(): FormArray<FormGroup> {
    return this.form.get('sales') as FormArray<FormGroup>;
  }

  get totalAmount(): number {
    return this.salesFormArray.controls.reduce((sum, group) => {
      return sum + Number(group.get('total')?.value ?? 0);
    }, 0);
  }

  get amountPaid(): number {
    return Number(this.form.get('amountPaid')?.value ?? 0);
  }

  get balanceAmount(): number {
    return Math.max(this.totalAmount - this.amountPaid, 0);
  }

  get computedPayType(): number {
    return this.balanceAmount > 0 ? 2 : 1;
  }

  get computedStatusLabel(): string {
    if (this.amountPaid >= this.totalAmount && this.totalAmount > 0) {
      return 'Pagado';
    }

    if (this.amountPaid > 0 && this.amountPaid < this.totalAmount) {
      return 'Parcial';
    }

    return 'Pendiente';
  }

  get hasRequiredCatalogs(): boolean {
    return this.branches.length > 0 && this.saleCatalog.length > 0 && this.users.length > 0;
  }

  get receivableAccount(): ReceivableAccountSummary | null {
    return this.createdResult?.receivableAccount ?? this.createdResult?.receivable ?? null;
  }

  get createdTicket(): ticket | CreateTicketResponse | null {
    return this.createdResult?.ticket ?? this.createdResult;
  }

  addSaleLine(): void {
    this.salesFormArray.push(this.createSaleLineGroup(this.currentUser?.id ?? this.users[0]?.id ?? null));
  }

  removeSaleLine(index: number): void {
    if (this.salesFormArray.length === 1) {
      return;
    }

    this.salesFormArray.removeAt(index);
  }

  getProductName(productId: number): string {
    return this.saleCatalog.find(product => product.id === productId)?.name ?? `Producto #${productId}`;
  }

  getSellerName(userId: number): string {
    return this.users.find(user => user.id === userId)?.name ?? `Usuario #${userId}`;
  }

  getBranchName(branchId: number): string {
    return this.branches.find(branch => branch.id === branchId)?.name ?? `Sucursal #${branchId}`;
  }

  getSaleLinePreview(index: number): SaleLineView | null {
    const group = this.salesFormArray.at(index);
    if (!group) {
      return null;
    }

    const productSaleId = Number(group.get('productSaleId')?.value ?? 0);
    const userId = Number(group.get('userId')?.value ?? 0);
    const volume = Number(group.get('volume')?.value ?? 0);
    const total = Number(group.get('total')?.value ?? 0);
    const unitPrice = volume > 0 ? total / volume : 0;

    return {
      productName: this.getProductName(productSaleId),
      sellerName: this.getSellerName(userId),
      volume,
      unitPrice,
      total
    };
  }

  getCommissionOptions(branchId?: number | null, userId?: number | null) {
    return this.commissions
      .filter(commission => {
        const branchMatch = !branchId || commission.branchId === branchId;
        const userMatch = !userId || commission.userId === userId;
        return branchMatch && userMatch;
      })
      .map(commission => ({
        label: `#${commission.id} - ${this.getSellerName(commission.userId)}`,
        value: commission.id
      }));
  }

  submit(): void {
    this.successMessage = '';
    this.createdResult = null;
    this.errorMessage = '';

    if (!this.hasRequiredCatalogs) {
      this.errorMessage = 'Necesitas sucursales, productos y usuarios para crear una venta.';
      return;
    }

    if (this.form.invalid || this.totalAmount <= 0) {
      this.form.markAllAsTouched();
      this.errorMessage = 'Revisa los datos de la venta antes de continuar.';
      return;
    }

    if (!this.currentUser?.id) {
      this.errorMessage = 'No se pudo identificar el usuario autenticado.';
      return;
    }

    this.submitting = true;

    const raw = this.form.getRawValue();
    const payload: ticket = {
      branchId: Number(raw.branchId),
      createdByUserId: this.currentUser.id,
      payType: this.computedPayType,
      invoiced: !!raw.invoiced,
      uuid: raw.uuid || null,
      invoiceDate: raw.invoiced && raw.invoiceDate ? new Date(raw.invoiceDate).toISOString() : null,
      folio: raw.folio,
      total: this.totalAmount,
      amountPaid: this.amountPaid,
      paymentMethod: raw.paymentMethod,
      dueDate: this.balanceAmount > 0 && raw.dueDate ? new Date(raw.dueDate).toISOString() : null,
      paymentReference: raw.paymentReference || null,
      notes: raw.notes || null,
      sales: raw.sales.map((line: any) => ({
        commissionId: line.commissionId ? Number(line.commissionId) : null,
        userId: Number(line.userId),
        volume: Number(line.volume),
        productSaleId: Number(line.productSaleId),
        total: Number(line.total)
      }))
    };

    this.ticketService.create(payload).subscribe({
      next: response => {
        this.submitting = false;
        this.createdResult = response;
        this.successMessage = 'La venta se creo correctamente.';
        this.resetForNextSale();
      },
      error: error => {
        this.submitting = false;
        this.errorMessage =
          error?.error?.message ||
          'No se pudo crear la venta. Verifica la informacion y vuelve a intentarlo.';
      }
    });
  }

  trackByIndex(index: number): number {
    return index;
  }

  private loadInitialData(): void {
    this.loading = true;
    this.errorMessage = '';

    forkJoin({
      profile: this.authService.getProfile(),
      branches: this.branchService.getAllBranches(),
      saleCatalog: this.saleService.getAll(),
      users: this.userService.getAllUsers(),
      commissions: this.commissionService.getAll()
    }).subscribe({
      next: ({ profile, branches, saleCatalog, users, commissions }) => {
        this.currentUser = profile;
        this.branches = branches;
        this.saleCatalog = saleCatalog;
        this.users = users;
        this.commissions = commissions;

        this.form.patchValue({
          createdByUserId: profile.id
        });

        if (this.branches.length === 1) {
          this.form.patchValue({ branchId: this.branches[0].id ?? null });
        }

        this.salesFormArray.controls.forEach(group => {
          group.patchValue({
            userId: profile.id
          });
        });

        this.loading = false;
      },
      error: () => {
        this.loading = false;
        this.errorMessage = 'No se pudieron cargar los catalogos para nueva venta.';
      }
    });
  }

  private watchDynamicRules(): void {
    this.form.get('invoiced')?.valueChanges.subscribe(invoiced => {
      const uuidControl = this.form.get('uuid');
      const invoiceDateControl = this.form.get('invoiceDate');

      if (invoiced) {
        invoiceDateControl?.setValidators([Validators.required]);
      } else {
        uuidControl?.setValue('');
        invoiceDateControl?.setValue('');
        invoiceDateControl?.clearValidators();
      }

      invoiceDateControl?.updateValueAndValidity({ emitEvent: false });
    });

    this.salesFormArray.valueChanges.subscribe(() => {
      this.salesFormArray.controls.forEach(group => this.recalculateLineTotal(group));
      this.form.updateValueAndValidity({ emitEvent: false });
    });
  }

  private createSaleLineGroup(defaultUserId: number | null = null): FormGroup {
    const group = this.fb.group({
      productSaleId: [null, Validators.required],
      userId: [defaultUserId, Validators.required],
      commissionId: [null],
      volume: [1, [Validators.required, Validators.min(1)]],
      total: [{ value: 0, disabled: false }, [Validators.required, Validators.min(0.01)]]
    });

    group.get('productSaleId')?.valueChanges.subscribe(() => this.recalculateLineTotal(group));
    group.get('volume')?.valueChanges.subscribe(() => this.recalculateLineTotal(group));

    return group;
  }

  private recalculateLineTotal(group: AbstractControl): void {
    const productId = Number(group.get('productSaleId')?.value ?? 0);
    const volume = Number(group.get('volume')?.value ?? 0);
    const product = this.saleCatalog.find(item => item.id === productId);
    const total = product ? Number(product.price ?? 0) * volume : 0;

    group.get('total')?.setValue(total, { emitEvent: false });
  }

  private creditDueDateValidator() {
    return (control: AbstractControl): ValidationErrors | null => {
      const paymentMethod = control.get('paymentMethod')?.value as TicketPaymentMethod;
      const dueDate = control.get('dueDate')?.value;
      const amountPaid = Number(control.get('amountPaid')?.value ?? 0);
      const sales = control.get('sales') as FormArray<FormGroup>;
      const total = sales?.controls.reduce((sum, group) => sum + Number(group.get('total')?.value ?? 0), 0) ?? 0;
      const hasPendingBalance = total - amountPaid > 0;

      if (paymentMethod === 'CREDIT' && hasPendingBalance && !dueDate) {
        return { dueDateRequiredForCredit: true };
      }

      return null;
    };
  }

  private amountPaidValidator() {
    return (control: AbstractControl): ValidationErrors | null => {
      const amountPaid = Number(control.get('amountPaid')?.value ?? 0);
      const sales = control.get('sales') as FormArray<FormGroup>;
      const total = sales?.controls.reduce((sum, group) => sum + Number(group.get('total')?.value ?? 0), 0) ?? 0;

      if (amountPaid > total) {
        return { amountPaidExceedsTotal: true };
      }

      return null;
    };
  }

  private resetForNextSale(): void {
    const currentUserId = this.currentUser?.id ?? null;
    const branchId = this.form.get('branchId')?.value;

    this.form.reset({
      branchId,
      createdByUserId: currentUserId,
      folio: '',
      invoiced: false,
      uuid: '',
      invoiceDate: '',
      amountPaid: 0,
      paymentMethod: 'CASH',
      dueDate: '',
      paymentReference: '',
      notes: ''
    });

    while (this.salesFormArray.length > 1) {
      this.salesFormArray.removeAt(this.salesFormArray.length - 1);
    }

    this.salesFormArray.at(0).reset({
      productSaleId: null,
      userId: currentUserId,
      commissionId: null,
      volume: 1,
      total: 0
    });
  }
}
