import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { forkJoin } from 'rxjs';

import { SidebarComponent } from '../../components/sidebar/sidebar.component';
import { Branch } from '../../models/branch.model';
import { Client } from '../../models/client.model';
import { ReceivableSummary, ReceivableSummaryClientItem } from '../../models/receivable-summary.model';
import { Receivable, ReceivableStatus } from '../../models/receivable.model';
import { ticket } from '../../models/Ticket.model';
import { User } from '../../models/user.model';
import { BranchService } from '../../services/branch.service';
import { BrowserStorageService } from '../../services/browser-storage.service';
import { ClientService } from '../../services/client.service';
import { ReceivableFilters, ReceivableService } from '../../services/receivable.service';
import { TicketService } from '../../services/ticket.service';
import { UserService } from '../../services/user.service';
import { PageTopbarComponent } from '../../shared/components/page-topbar/page-topbar.component';
import { ReceivableDetailPage } from './receivable-detail/receivable-detail.page';
import { ReceivablePaymentPage } from './receivable-payment/receivable-payment.page';
import { ReceivableFormPage } from './receivable-form/receivable-form.page';

interface PageMessage {
  type: 'success' | 'error';
  text: string;
}

@Component({
  selector: 'app-cobranza',
  standalone: true,
  imports: [CommonModule, FormsModule, SidebarComponent, PageTopbarComponent],
  templateUrl: './cobranza.page.html',
  styleUrls: ['./cobranza.page.scss']
})
export class CobranzaPage implements OnInit {
  receivables: Receivable[] = [];
  summary: ReceivableSummary | null = null;
  clients: Client[] = [];
  branches: Branch[] = [];
  tickets: ticket[] = [];
  users: User[] = [];

  filters: ReceivableFilters = {
    clientId: '',
    branchId: '',
    ticketId: '',
    status: '',
    from: '',
    to: ''
  };

  loading = true;
  summaryLoading = true;
  lookupsLoading = true;

  errorMessage = '';
  summaryError = '';
  lookupsError = '';
  message: PageMessage | null = null;

  readonly statusOptions = [
    { label: 'Todos', value: '' },
    { label: 'Pendiente', value: 'PENDING' },
    { label: 'Parcial', value: 'PARTIAL' },
    { label: 'Pagado', value: 'PAID' },
    { label: 'Vencido', value: 'OVERDUE' },
    { label: 'Cancelado', value: 'CANCELLED' }
  ];

  private readonly filterStorageKey = 'receivables.filters';

  constructor(
    private receivableService: ReceivableService,
    private clientService: ClientService,
    private branchService: BranchService,
    private ticketService: TicketService,
    private userService: UserService,
    private storage: BrowserStorageService,
    private dialog: MatDialog
  ) {}

  ngOnInit(): void {
    this.filters = this.storage.getObject<ReceivableFilters>(this.filterStorageKey, this.filters);
    this.loadInitialData();
  }

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

    forkJoin({
      clients: this.clientService.getAllClients(),
      branches: this.branchService.getAllBranches(),
      tickets: this.ticketService.getAll(),
      users: this.userService.getAllUsers()
    }).subscribe({
      next: ({ clients, branches, tickets, users }) => {
        this.clients = clients;
        this.branches = branches;
        this.tickets = tickets;
        this.users = users;
        this.lookupsLoading = false;
        this.loadReceivables();
        this.loadSummary();
      },
      error: () => {
        this.lookupsLoading = false;
        this.loading = false;
        this.summaryLoading = false;
        this.lookupsError = 'No se pudieron cargar los catalogos de cobranza.';
      }
    });
  }

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

    this.receivableService.getAll(this.filters).subscribe({
      next: receivables => {
        this.receivables = receivables;
        this.loading = false;
      },
      error: () => {
        this.loading = false;
        this.errorMessage = 'No se pudieron cargar las cuentas por cobrar.';
      }
    });
  }

  loadSummary(): void {
    this.summaryLoading = true;
    this.summaryError = '';

    this.receivableService.getSummary(this.filters).subscribe({
      next: summary => {
        this.summary = summary;
        this.summaryLoading = false;
      },
      error: () => {
        this.summaryLoading = false;
        this.summaryError = 'No se pudo cargar el resumen de cobranza.';
      }
    });
  }

  applyFilters(): void {
    this.storage.setObject(this.filterStorageKey, this.filters);
    this.loadReceivables();
    this.loadSummary();
  }

  resetFilters(): void {
    this.filters = {
      clientId: '',
      branchId: '',
      ticketId: '',
      status: '',
      from: '',
      to: ''
    };
    this.storage.removeItem(this.filterStorageKey);
    this.applyFilters();
  }

  openFormModal(receivable?: Receivable): void {
    const dialogRef = this.dialog.open(ReceivableFormPage, {
      width: '860px',
      data: {
        receivable: receivable ?? null,
        clients: this.clients,
        branches: this.branches,
        tickets: this.tickets,
        users: this.users
      }
    });

    dialogRef.afterClosed().subscribe(result => {
      if (!result?.saved) {
        return;
      }

      this.message = { type: 'success', text: result.message };
      this.loadReceivables();
      this.loadSummary();
    });
  }

  openDetailModal(receivable: Receivable): void {
    if (!receivable.id) {
      return;
    }

    const dialogRef = this.dialog.open(ReceivableDetailPage, {
      width: '920px',
      data: {
        receivableId: receivable.id,
        clients: this.clients,
        branches: this.branches,
        tickets: this.tickets,
        users: this.users
      }
    });

    dialogRef.afterClosed().subscribe(result => {
      if (!result?.refresh) {
        return;
      }

      if (result?.message) {
        this.message = { type: 'success', text: result.message };
      }

      this.loadReceivables();
      this.loadSummary();
    });
  }

  openPaymentModal(receivable: Receivable): void {
    if (!receivable.id) {
      return;
    }

    const dialogRef = this.dialog.open(ReceivablePaymentPage, {
      width: '720px',
      data: {
        receivableId: receivable.id,
        users: this.users
      }
    });

    dialogRef.afterClosed().subscribe(result => {
      if (!result?.saved) {
        return;
      }

      this.message = { type: 'success', text: result.message };
      this.loadReceivables();
      this.loadSummary();
    });
  }

  deleteReceivable(receivable: Receivable): void {
    if (!receivable.id) {
      return;
    }

    if (!this.storage.isBrowser() || !window.confirm(`Eliminar la cuenta "${receivable.reference || receivable.description}"?`)) {
      return;
    }

    this.receivableService.delete(receivable.id).subscribe({
      next: () => {
        this.message = { type: 'success', text: 'Cuenta por cobrar eliminada correctamente.' };
        this.loadReceivables();
        this.loadSummary();
      },
      error: () => {
        this.message = { type: 'error', text: 'No se pudo eliminar la cuenta por cobrar.' };
      }
    });
  }

  getClientName(clientId: number): string {
    return this.clients.find(client => client.id === clientId)?.name ?? `Cliente #${clientId}`;
  }

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

  getTicketLabel(ticketId: number): string {
    const ticketRecord = this.tickets.find(ticketItem => ticketItem.id === ticketId);
    return ticketRecord?.folio || ticketRecord?.uuid || `Ticket #${ticketId}`;
  }

  getStatusLabel(status: ReceivableStatus): string {
    switch (status) {
      case 'PARTIAL':
        return 'Parcial';
      case 'PAID':
        return 'Pagado';
      case 'OVERDUE':
        return 'Vencido';
      case 'CANCELLED':
        return 'Cancelado';
      default:
        return 'Pendiente';
    }
  }

  getPaidAmount(receivable: Receivable): number {
    return Number(
      receivable.paidAmount ??
      this.getPayments(receivable).reduce((sum, payment) => sum + Number(payment.amount ?? 0), 0)
    );
  }

  getBalanceAmount(receivable: Receivable): number {
    const fallbackBalance = Number(receivable.totalAmount ?? 0) - this.getPaidAmount(receivable);
    return Number(receivable.balanceAmount ?? fallbackBalance);
  }

  getSummaryClientName(item: ReceivableSummaryClientItem): string {
    return item.clientName ?? item.name ?? 'Sin cliente';
  }

  getSummaryClientAmount(item: ReceivableSummaryClientItem): number {
    return Number(item.totalAmount ?? item.amount ?? 0);
  }

  getRowClass(receivable: Receivable): string {
    switch (receivable.status) {
      case 'OVERDUE':
        return 'row-overdue';
      case 'PARTIAL':
        return 'row-partial';
      default:
        return '';
    }
  }

  hasReceivables(): boolean {
    return this.receivables.length > 0;
  }

  private getPayments(receivable: Receivable) {
    return receivable.payments ?? receivable.receivablePayments ?? [];
  }
}
