import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { ChartData, ChartOptions } from 'chart.js';
import { forkJoin } from 'rxjs';

import { SidebarComponent } from '../../components/sidebar/sidebar.component';
import {
  ExpensesKpiResponse,
  OverviewKpiResponse,
  ReceivablesKpiResponse,
  SalesKpiResponse
} from '../../models/report-kpi.model';
import { ReportsService } from '../../services/reports.service';
import { PageTopbarComponent } from '../../shared/components/page-topbar/page-topbar.component';
import { DashboardChartCardComponent } from './components/dashboard-chart-card.component';
import { DashboardFilterComponent } from './components/dashboard-filter.component';
import { DashboardKpiCardComponent } from './components/dashboard-kpi-card.component';

interface DashboardKpiCardView {
  label: string;
  value: string;
  detail: string;
  trendLabel: string;
  tone: 'sales' | 'expenses' | 'net' | 'receivables' | 'neutral';
}

@Component({
  standalone: true,
  selector: 'app-dashboard',
  imports: [
    CommonModule,
    SidebarComponent,
    PageTopbarComponent,
    DashboardFilterComponent,
    DashboardKpiCardComponent,
    DashboardChartCardComponent
  ],
  templateUrl: './dashboard.page.html',
  styleUrls: ['./dashboard.page.scss']
})
export class DashboardPage implements OnInit {
  readonly loadingCards = Array.from({ length: 6 }, (_, index) => index);
  selectedDate = this.getToday();
  loading = true;
  errorMessage = '';

  overview: OverviewKpiResponse | null = null;
  salesKpi: SalesKpiResponse | null = null;
  receivablesKpi: ReceivablesKpiResponse | null = null;
  expensesKpi: ExpensesKpiResponse | null = null;

  comparisonChartData: ChartData<'bar'> = { labels: [], datasets: [] };
  comparisonChartOptions: ChartOptions<'bar'> = this.buildBarOptions('Comparativa mensual');

  salesPaymentMethodChartData: ChartData<'doughnut'> = { labels: [], datasets: [] };
  salesPaymentMethodChartOptions: ChartOptions<'doughnut'> = this.buildDoughnutOptions();

  salesStatusChartData: ChartData<'bar'> = { labels: [], datasets: [] };
  salesStatusChartOptions: ChartOptions<'bar'> = this.buildBarOptions('Estado de ventas');

  receivablesStatusChartData: ChartData<'doughnut'> = { labels: [], datasets: [] };
  receivablesStatusChartOptions: ChartOptions<'doughnut'> = this.buildDoughnutOptions();

  expensesByCategoryChartData: ChartData<'bar'> = { labels: [], datasets: [] };
  expensesByCategoryChartOptions: ChartOptions<'bar'> = this.buildHorizontalBarOptions();

  expensesByCenterChartData: ChartData<'doughnut'> = { labels: [], datasets: [] };
  expensesByCenterChartOptions: ChartOptions<'doughnut'> = this.buildDoughnutOptions();

  readonly kpiCards: DashboardKpiCardView[] = [];

  constructor(private reportsService: ReportsService) {}

  ngOnInit(): void {
    this.loadDashboard();
  }

  onDateChange(date: string): void {
    this.selectedDate = date;
    this.loadDashboard();
  }

  get dashboardCards(): DashboardKpiCardView[] {
    if (!this.overview || !this.salesKpi || !this.receivablesKpi || !this.expensesKpi) {
      return [];
    }

    return [
      {
        label: 'Ventas del mes',
        value: this.formatCurrency(this.overview.sales.currentMonth),
        detail: `${this.overview.sales.ticketCountCurrentMonth} tickets en el periodo`,
        trendLabel: this.formatTrend('vs. mes anterior', this.overview.sales.change.percentage),
        tone: 'sales'
      },
      {
        label: 'Gastos del mes',
        value: this.formatCurrency(this.overview.expenses.currentMonth),
        detail: `${this.overview.expenses.recordCountCurrentMonth} registros de gasto`,
        trendLabel: this.formatTrend('vs. mes anterior', this.overview.expenses.change.percentage),
        tone: 'expenses'
      },
      {
        label: 'Neto del mes',
        value: this.formatCurrency(this.overview.net.currentMonth),
        detail: `Resultado del periodo actual`,
        trendLabel: this.formatTrend('vs. mes anterior', this.overview.net.change.percentage),
        tone: 'net'
      },
      {
        label: 'Pendiente por cobrar',
        value: this.formatCurrency(this.receivablesKpi.totals.totalPendingAmount),
        detail: `${this.receivablesKpi.totals.pendingCount} cuentas pendientes`,
        trendLabel: `${this.receivablesKpi.totals.overdueCount} vencidas`,
        tone: 'receivables'
      },
      {
        label: 'Tickets del mes',
        value: this.formatNumber(this.overview.sales.ticketCountCurrentMonth),
        detail: `${this.formatCurrency(this.salesKpi.totals.totalCollected)} cobrados`,
        trendLabel: `${this.salesKpi.byPaymentMethod.length} metodos activos`,
        tone: 'sales'
      },
      {
        label: 'Registros de gasto',
        value: this.formatNumber(this.overview.expenses.recordCountCurrentMonth),
        detail: `${this.formatCurrency(this.expensesKpi.totals.totalPaid)} pagados`,
        trendLabel: `${this.expensesKpi.byCategory.length} categorias activas`,
        tone: 'expenses'
      }
    ];
  }

  get hasAnyData(): boolean {
    return !!(this.overview || this.salesKpi || this.receivablesKpi || this.expensesKpi);
  }

  get periodLabel(): string {
    if (!this.overview?.period.currentStart || !this.overview.period.currentEnd) {
      return 'Sin periodo disponible';
    }

    return `${this.formatDate(this.overview.period.currentStart)} al ${this.formatDate(this.overview.period.currentEnd)}`;
  }

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

    forkJoin({
      overview: this.reportsService.getOverview(this.selectedDate),
      sales: this.reportsService.getSales(this.selectedDate),
      receivables: this.reportsService.getReceivables(this.selectedDate),
      expenses: this.reportsService.getExpenses(this.selectedDate)
    }).subscribe({
      next: ({ overview, sales, receivables, expenses }) => {
        this.overview = overview;
        this.salesKpi = sales;
        this.receivablesKpi = receivables;
        this.expensesKpi = expenses;
        this.buildCharts();
        this.loading = false;
      },
      error: error => {
        this.loading = false;
        this.errorMessage =
          error?.status === 401
            ? 'La sesion ya no es valida. Inicia sesion de nuevo para consultar los KPI.'
            : 'No se pudieron cargar los indicadores del dashboard.';
      }
    });
  }

  private buildCharts(): void {
    if (!this.overview || !this.salesKpi || !this.receivablesKpi || !this.expensesKpi) {
      return;
    }

    this.comparisonChartData = {
      labels: ['Ventas', 'Gastos', 'Neto'],
      datasets: [
        {
          label: 'Mes actual',
          data: [
            this.overview.sales.currentMonth,
            this.overview.expenses.currentMonth,
            this.overview.net.currentMonth
          ],
          backgroundColor: ['#1b9ac0', '#d98c43', '#627ed8'],
          borderRadius: 14,
          maxBarThickness: 34
        },
        {
          label: 'Mes anterior',
          data: [
            this.overview.sales.previousMonth,
            this.overview.expenses.previousMonth,
            this.overview.net.previousMonth
          ],
          backgroundColor: ['#b8deea', '#f3c68e', '#c9d2ff'],
          borderRadius: 14,
          maxBarThickness: 34
        }
      ]
    };

    this.salesPaymentMethodChartData = {
      labels: this.salesKpi.byPaymentMethod.map(item => this.getPaymentMethodLabel(item.paymentMethod)),
      datasets: [
        {
          data: this.salesKpi.byPaymentMethod.map(item => item.totalSales),
          backgroundColor: ['#167d96', '#2f9b83', '#627ed8', '#c67852', '#9b7ad1'],
          hoverOffset: 10
        }
      ]
    };

    this.salesStatusChartData = {
      labels: this.salesKpi.byStatus.map(item => this.getStatusLabel(item.status)),
      datasets: [
        {
          label: 'Ventas',
          data: this.salesKpi.byStatus.map(item => item.totalSales),
          backgroundColor: '#1b9ac0',
          borderRadius: 14,
          maxBarThickness: 42
        },
        {
          label: 'Pendiente',
          data: this.salesKpi.byStatus.map(item => item.totalPending),
          backgroundColor: '#f0b35f',
          borderRadius: 14,
          maxBarThickness: 42
        }
      ]
    };

    this.receivablesStatusChartData = {
      labels: this.receivablesKpi.byStatus.map(item => this.getStatusLabel(item.status)),
      datasets: [
        {
          data: this.receivablesKpi.byStatus.map(item => item.balanceAmount),
          backgroundColor: ['#2f9b83', '#e7a443', '#cf6670', '#627ed8', '#9b7ad1'],
          hoverOffset: 10
        }
      ]
    };

    this.expensesByCategoryChartData = {
      labels: this.expensesKpi.byCategory.map(item => item.categoryName),
      datasets: [
        {
          label: 'Monto total',
          data: this.expensesKpi.byCategory.map(item => item.totalAmount),
          backgroundColor: '#d98c43',
          borderRadius: 16,
          maxBarThickness: 28
        }
      ]
    };

    this.expensesByCenterChartData = {
      labels: this.expensesKpi.byExpenseCenter.map(item => item.expenseCenterName),
      datasets: [
        {
          data: this.expensesKpi.byExpenseCenter.map(item => item.totalAmount),
          backgroundColor: ['#c67852', '#0f617f', '#2f9b83', '#627ed8', '#9b7ad1', '#e7a443'],
          hoverOffset: 10
        }
      ]
    };
  }

  private buildBarOptions(label: string): ChartOptions<'bar'> {
    return {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: {
          display: true,
          position: 'top',
          labels: {
            usePointStyle: true,
            pointStyle: 'circle'
          }
        },
        tooltip: {
          callbacks: {
            label: context => `${context.dataset.label}: ${this.formatCurrency(Number(context.raw ?? 0))}`
          }
        }
      },
      scales: {
        x: {
          grid: {
            display: false
          }
        },
        y: {
          beginAtZero: true,
          ticks: {
            callback: value => this.formatCompactCurrency(Number(value))
          }
        }
      }
    };
  }

  private buildHorizontalBarOptions(): ChartOptions<'bar'> {
    return {
      responsive: true,
      maintainAspectRatio: false,
      indexAxis: 'y',
      plugins: {
        legend: {
          display: false
        },
        tooltip: {
          callbacks: {
            label: context => `${context.dataset.label}: ${this.formatCurrency(Number(context.raw ?? 0))}`
          }
        }
      },
      scales: {
        x: {
          beginAtZero: true,
          ticks: {
            callback: value => this.formatCompactCurrency(Number(value))
          }
        },
        y: {
          grid: {
            display: false
          }
        }
      }
    };
  }

  private buildDoughnutOptions(): ChartOptions<'doughnut'> {
    return {
      responsive: true,
      maintainAspectRatio: false,
      cutout: '62%',
      plugins: {
        legend: {
          position: 'bottom',
          labels: {
            usePointStyle: true,
            pointStyle: 'circle',
            padding: 18
          }
        },
        tooltip: {
          callbacks: {
            label: context => `${context.label}: ${this.formatCurrency(Number(context.raw ?? 0))}`
          }
        }
      }
    };
  }

  private getPaymentMethodLabel(method: string): string {
    switch (method) {
      case 'TRANSFER':
        return 'Transferencia';
      case 'CARD':
        return 'Tarjeta';
      case 'CREDIT':
        return 'Credito';
      case 'OTHER':
        return 'Otro';
      default:
        return 'Efectivo';
    }
  }

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

  formatCurrency(value: number): string {
    return new Intl.NumberFormat('es-MX', {
      style: 'currency',
      currency: 'MXN',
      minimumFractionDigits: 2
    }).format(value ?? 0);
  }

  private formatCompactCurrency(value: number): string {
    return new Intl.NumberFormat('es-MX', {
      style: 'currency',
      currency: 'MXN',
      notation: 'compact',
      maximumFractionDigits: 1
    }).format(value ?? 0);
  }

  formatNumber(value: number): string {
    return new Intl.NumberFormat('es-MX').format(value ?? 0);
  }

  private formatTrend(prefix: string, percentage: number | null): string {
    if (percentage === null || Number.isNaN(percentage)) {
      return `${prefix}: sin base anterior`;
    }

    const sign = percentage > 0 ? '+' : '';
    return `${prefix}: ${sign}${percentage.toFixed(1)}%`;
  }

  private formatDate(value: string): string {
    return new Intl.DateTimeFormat('es-MX', {
      day: '2-digit',
      month: 'short',
      year: 'numeric'
    }).format(new Date(value));
  }

  private getToday(): string {
    return new Date().toISOString().slice(0, 10);
  }
}
