import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Router } from '@angular/router';
import {
  AuthService,
  EstadisticasAutorizaciones,
  EstadisticasAutorizacionesDia,
} from '../../services/auth';
import { AppHeaderComponent } from '../shared/app-header/app-header';
import { finalize } from 'rxjs/operators';

@Component({
  selector: 'app-estadisticas-autorizaciones',
  standalone: true,
  imports: [CommonModule, FormsModule, AppHeaderComponent],
  templateUrl: './estadisticas-autorizaciones.html',
  styleUrls: ['./estadisticas-autorizaciones.css']
})
export class EstadisticasAutorizacionesComponent implements OnInit {
  titulo = 'Estadisticas de autorizaciones';
  mesSeleccionado = '';
  anioSeleccionado = '';
  periodo: 'dia' | 'semana' | 'mes' | 'anio' = 'mes';
  isLoading = false;
  errorMessage: string | null = null;
  data: EstadisticasAutorizaciones | null = null;
  maxTotal = 0;
  chartBuckets: ChartBucket[] = [];
  selectedBucket: ChartBucket | null = null;
  autorizacionesDetalle: any[] = [];
  isLoadingDetalle = false;
  errorDetalle: string | null = null;
  detalleLimitado = false;
  tienePendientes = false;

  constructor(
    public authService: AuthService,
    private router: Router,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    if (!this.authService.isAdministrador()) {
      this.errorMessage = 'No tienes permisos para acceder a esta pagina.';
      return;
    }

    const hoy = new Date();
    this.anioSeleccionado = String(hoy.getFullYear());
    this.mesSeleccionado = this.formatMonthInput(hoy);
    this.cargarEstadisticas();
  }

  onPeriodoChange(): void {
    const hoy = new Date();
    if (this.periodo === 'dia' || this.periodo === 'semana') {
      if (!this.mesSeleccionado) {
        this.mesSeleccionado = this.formatMonthInput(hoy);
      }
    }
    if ((this.periodo === 'mes' || this.periodo === 'anio') && !this.anioSeleccionado) {
      this.anioSeleccionado = String(hoy.getFullYear());
    }
    this.cargarEstadisticas();
  }

  cargarEstadisticas(): void {
    this.errorMessage = null;
    this.selectedBucket = null;
    this.autorizacionesDetalle = [];
    this.errorDetalle = null;
    this.detalleLimitado = false;

    let inicio = '';
    let fin = '';

    if (this.periodo === 'dia') {
      if (!this.mesSeleccionado) {
        this.errorMessage = 'Selecciona un mes para consultar.';
        return;
      }
      [inicio, fin] = this.getRangoMes(this.mesSeleccionado);
    } else if (this.periodo === 'semana') {
      if (!this.mesSeleccionado) {
        this.errorMessage = 'Selecciona un mes para consultar.';
        return;
      }
      [inicio, fin] = this.getRangoMes(this.mesSeleccionado);
    } else if (this.periodo === 'mes') {
      if (!this.anioSeleccionado) {
        this.errorMessage = 'Selecciona un año para consultar.';
        return;
      }
      [inicio, fin] = this.getRangoAnio(this.anioSeleccionado);
    } else {
      if (!this.anioSeleccionado) {
        this.errorMessage = 'Selecciona un año para consultar.';
        return;
      }
      [inicio, fin] = this.getRangoAnios(this.anioSeleccionado);
    }

    if (!inicio || !fin) {
      this.errorMessage = 'Rango de fechas invalido.';
      return;
    }

    this.isLoading = true;
    this.data = null;
    this.maxTotal = 0;

    this.authService
      .getEstadisticasAutorizaciones(inicio, fin)
      .pipe(
        finalize(() => {
          this.isLoading = false;
          this.cdr.markForCheck();
        })
      )
      .subscribe({
        next: (resp) => {
          this.data = resp;
          this.chartBuckets = this.buildBuckets(resp?.dias || [], resp?.rango);
          this.maxTotal = Math.max(
            1,
            ...(this.chartBuckets.map((b) => Number(b.total) || 0))
          );
          this.tienePendientes = Number(resp?.resumen?.pendientes) > 0;
        },
        error: (err) => {
          console.error(err);
          this.errorMessage =
            err?.error?.error || 'Error consultando estadisticas.';
        },
      });
  }

  volverAtras(): void {
    this.router.navigate(['/dashboard']);
  }

  getBarHeight(bucket: ChartBucket): string {
    if (!this.maxTotal) return '0%';
    const total = Number(bucket.total) || 0;
    const percent = Math.max(0, Math.min(100, (total / this.maxTotal) * 100));
    return `${percent}%`;
  }

  getSegmentHeight(
    bucket: ChartBucket,
    key: 'autorizadas' | 'no_autorizadas' | 'pendientes'
  ): string {
    const total = Number(bucket.total) || 0;
    if (!total) return '0%';
    const value = Number(bucket[key]) || 0;
    const percent = Math.max(0, Math.min(100, (value / total) * 100));
    return `${percent}%`;
  }

  seleccionarBucket(bucket: ChartBucket): void {
    if (!bucket?.inicio || !bucket?.fin) {
      return;
    }

    this.selectedBucket = bucket;
    this.autorizacionesDetalle = [];
    this.errorDetalle = null;
    this.detalleLimitado = false;
    this.isLoadingDetalle = false;

    const total = Number(bucket.total) || 0;
    if (!total) {
      return;
    }

    this.isLoadingDetalle = true;

    this.authService
      .getAutorizacionesPorFecha(bucket.inicio, bucket.fin, 500, 0)
      .pipe(
        finalize(() => {
          this.isLoadingDetalle = false;
          this.cdr.markForCheck();
        })
      )
      .subscribe({
        next: (resp) => {
          this.autorizacionesDetalle = resp || [];
          this.detalleLimitado = this.autorizacionesDetalle.length >= 500;
        },
        error: (err) => {
          console.error(err);
          this.errorDetalle =
            err?.error?.error || 'Error consultando autorizaciones del rango.';
        }
      });
  }

  limpiarDetalle(): void {
    this.selectedBucket = null;
    this.autorizacionesDetalle = [];
    this.errorDetalle = null;
    this.detalleLimitado = false;
  }

  formatDateLabel(fecha: string): string {
    const date = new Date(fecha);
    if (Number.isNaN(date.getTime())) return fecha;
    return date.toLocaleDateString('es-CO', {
      weekday: 'short',
      year: 'numeric',
      month: 'short',
      day: 'numeric'
    });
  }

  formatRangeLabel(inicio: string, fin: string): string {
    if (inicio === fin) {
      return this.formatDateLabel(inicio);
    }
    return `${this.formatDateLabel(inicio)} - ${this.formatDateLabel(fin)}`;
  }

  getEstadoAutorizacionLabel(estado: string | null | undefined): string {
    const normalizado = String(estado || 'pendiente').toLowerCase();
    if (normalizado === 'autorizado') {
      return 'Autorizado';
    }
    if (normalizado === 'no_autorizado') {
      return 'No autorizado';
    }
    return 'Pendiente';
  }

  private getRangoMes(mes: string): [string, string] {
    const [yearStr, monthStr] = mes.split('-');
    const year = Number(yearStr);
    const monthIndex = Number(monthStr) - 1;
    const inicio = new Date(year, monthIndex, 1);
    const fin = new Date(year, monthIndex + 1, 0);

    const hoy = new Date();
    const esMesActual =
      hoy.getFullYear() === year && hoy.getMonth() === monthIndex;

    const fechaFin = esMesActual ? hoy : fin;
    return [this.formatDate(inicio), this.formatDate(fechaFin)];
  }

  private getRangoAnio(anio: string): [string, string] {
    const year = Number(anio);
    if (!year) {
      return ['', ''];
    }
    const inicio = new Date(year, 0, 1);
    const fin = new Date(year, 11, 31);
    const hoy = new Date();
    const esAnioActual = hoy.getFullYear() === year;
    const fechaFin = esAnioActual ? hoy : fin;
    return [this.formatDate(inicio), this.formatDate(fechaFin)];
  }

  private getRangoAnios(anio: string): [string, string] {
    const year = Number(anio);
    if (!year) {
      return ['', ''];
    }
    const inicio = new Date(year - 4, 0, 1);
    const fin = new Date(year, 11, 31);
    const hoy = new Date();
    const fechaFin = hoy < fin ? hoy : fin;
    return [this.formatDate(inicio), this.formatDate(fechaFin)];
  }

  private formatDate(date: Date): string {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  }

  private formatMonthInput(date: Date): string {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    return `${year}-${month}`;
  }

  private buildBuckets(
    dias: EstadisticasAutorizacionesDia[],
    rango?: { inicio: string; fin: string }
  ): ChartBucket[] {
    if (!rango) {
      return [];
    }

    if (this.periodo === 'dia') {
      return dias.map((dia) => {
        const date = new Date(dia.fecha);
        const label = Number.isNaN(date.getTime())
          ? ''
          : String(date.getDate());
        return {
          key: dia.fecha,
          label,
          inicio: dia.fecha,
          fin: dia.fecha,
          total: Number(dia.total) || 0,
          autorizadas: Number(dia.autorizadas) || 0,
          no_autorizadas: Number(dia.no_autorizadas) || 0,
          pendientes: Number(dia.pendientes) || 0,
        };
      });
    }

    const rangoInicio = new Date(rango.inicio);
    const rangoFin = new Date(rango.fin);

    if (this.periodo === 'semana') {
      const buckets = new Map<string, ChartBucket>();
      dias.forEach((dia) => {
        const date = new Date(dia.fecha);
        if (Number.isNaN(date.getTime())) return;
        const weekStart = this.getWeekStart(date);
        const weekEnd = this.addDays(weekStart, 6);
        const key = this.formatDate(weekStart);
        if (!buckets.has(key)) {
          const inicio = this.maxDate(weekStart, rangoInicio);
          const fin = this.minDate(weekEnd, rangoFin);
          buckets.set(key, {
            key,
            label: this.formatWeekLabel(inicio, fin),
            inicio: this.formatDate(inicio),
            fin: this.formatDate(fin),
            total: 0,
            autorizadas: 0,
            no_autorizadas: 0,
            pendientes: 0,
          });
        }
        const bucket = buckets.get(key)!;
        bucket.total += Number(dia.total) || 0;
        bucket.autorizadas += Number(dia.autorizadas) || 0;
        bucket.no_autorizadas += Number(dia.no_autorizadas) || 0;
        bucket.pendientes += Number(dia.pendientes) || 0;
      });
      return Array.from(buckets.values()).sort((a, b) =>
        a.inicio.localeCompare(b.inicio)
      );
    }

    if (this.periodo === 'mes') {
      const buckets = new Map<string, ChartBucket>();
      dias.forEach((dia) => {
        const date = new Date(dia.fecha);
        if (Number.isNaN(date.getTime())) return;
        const key = `${date.getFullYear()}-${date.getMonth()}`;
        if (!buckets.has(key)) {
          const inicio = new Date(date.getFullYear(), date.getMonth(), 1);
          const fin = new Date(date.getFullYear(), date.getMonth() + 1, 0);
          const inicioClamp = this.maxDate(inicio, rangoInicio);
          const finClamp = this.minDate(fin, rangoFin);
          buckets.set(key, {
            key,
            label: date.toLocaleDateString('es-CO', { month: 'short' }),
            inicio: this.formatDate(inicioClamp),
            fin: this.formatDate(finClamp),
            total: 0,
            autorizadas: 0,
            no_autorizadas: 0,
            pendientes: 0,
          });
        }
        const bucket = buckets.get(key)!;
        bucket.total += Number(dia.total) || 0;
        bucket.autorizadas += Number(dia.autorizadas) || 0;
        bucket.no_autorizadas += Number(dia.no_autorizadas) || 0;
        bucket.pendientes += Number(dia.pendientes) || 0;
      });
      return Array.from(buckets.values()).sort((a, b) =>
        a.inicio.localeCompare(b.inicio)
      );
    }

    const buckets = new Map<string, ChartBucket>();
    dias.forEach((dia) => {
      const date = new Date(dia.fecha);
      if (Number.isNaN(date.getTime())) return;
      const year = date.getFullYear();
      const key = String(year);
      if (!buckets.has(key)) {
        const inicio = new Date(year, 0, 1);
        const fin = new Date(year, 11, 31);
        const inicioClamp = this.maxDate(inicio, rangoInicio);
        const finClamp = this.minDate(fin, rangoFin);
        buckets.set(key, {
          key,
          label: key,
          inicio: this.formatDate(inicioClamp),
          fin: this.formatDate(finClamp),
          total: 0,
          autorizadas: 0,
          no_autorizadas: 0,
          pendientes: 0,
        });
      }
      const bucket = buckets.get(key)!;
      bucket.total += Number(dia.total) || 0;
      bucket.autorizadas += Number(dia.autorizadas) || 0;
      bucket.no_autorizadas += Number(dia.no_autorizadas) || 0;
      bucket.pendientes += Number(dia.pendientes) || 0;
    });
    return Array.from(buckets.values()).sort((a, b) =>
      a.inicio.localeCompare(b.inicio)
    );
  }

  private getWeekStart(date: Date): Date {
    const base = new Date(date);
    const day = base.getDay();
    const diffToMonday = (day + 6) % 7;
    base.setDate(base.getDate() - diffToMonday);
    base.setHours(0, 0, 0, 0);
    return base;
  }

  private addDays(date: Date, days: number): Date {
    const next = new Date(date);
    next.setDate(next.getDate() + days);
    return next;
  }

  private maxDate(a: Date, b: Date): Date {
    return a > b ? a : b;
  }

  private minDate(a: Date, b: Date): Date {
    return a < b ? a : b;
  }

  private formatWeekLabel(inicio: Date, fin: Date): string {
    const inicioDia = inicio.getDate();
    const finDia = fin.getDate();
    return `${inicioDia}-${finDia}`;
  }
}

type ChartBucket = {
  key: string;
  label: string;
  inicio: string;
  fin: string;
  total: number;
  autorizadas: number;
  no_autorizadas: number;
  pendientes: number;
};
