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

import { SidebarComponent } from '../../../components/sidebar/sidebar.component';
import { CatalogCrudConfig, CatalogLookupData } from '../../../models/catalog-crud.model';
import { CatalogCrudService } from '../../../services/catalog-crud.service';
import { TableComponent } from '../../../shared/components/table/table.component';
import { catalogCrudConfigMap } from './catalog-crud.config';
import { CatalogFormDialogPage } from './catalog-form-dialog.page';

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

@Component({
  selector: 'app-catalog-crud-page',
  standalone: true,
  imports: [CommonModule, FormsModule, SidebarComponent, TableComponent],
  templateUrl: './catalog-crud.page.html',
  styleUrls: ['./catalog-crud.page.scss']
})
export class CatalogCrudPage implements OnInit {
  config: CatalogCrudConfig | null = null;
  items: Record<string, unknown>[] = [];
  filteredItems: Record<string, unknown>[] = [];
  tableRows: Record<string, unknown>[] = [];
  lookupData: CatalogLookupData = {};

  loading = true;
  lookupLoading = true;
  errorMessage = '';
  searchTerm = '';
  message: PageMessage | null = null;

  constructor(
    private route: ActivatedRoute,
    private dialog: MatDialog,
    private catalogCrudService: CatalogCrudService
  ) {}

  ngOnInit(): void {
    const catalogKey = String(this.route.snapshot.data['catalogKey'] ?? '');
    const config = catalogCrudConfigMap[catalogKey];

    if (!config) {
      this.loading = false;
      this.lookupLoading = false;
      this.errorMessage = 'No se encontro la configuracion del catalogo.';
      return;
    }

    this.config = config;
    this.loadLookupsAndItems();
  }

  get tableHeaders(): string[] {
    return this.config?.columns.map(column => column.label) ?? [];
  }

  get tableKeys(): string[] {
    return this.config?.columns.map(column => column.key) ?? [];
  }

  loadLookupsAndItems(): void {
    if (!this.config) {
      return;
    }

    this.loading = true;
    this.lookupLoading = true;
    this.errorMessage = '';

    const lookupRequests = (this.config.lookups ?? []).reduce(
      (accumulator, lookup) => ({
        ...accumulator,
        [lookup.key]: this.catalogCrudService.list<Record<string, unknown>>(lookup.endpoint)
      }),
      {} as Record<string, Observable<Record<string, unknown>[]>>
    );

    if (Object.keys(lookupRequests).length === 0) {
      this.lookupData = {};
      this.lookupLoading = false;
      this.loadItems();
      return;
    }

    forkJoin(lookupRequests).subscribe({
      next: data => {
        this.lookupData = data;
        this.lookupLoading = false;
        this.loadItems();
      },
      error: () => {
        this.lookupLoading = false;
        this.loading = false;
        this.errorMessage = 'No se pudieron cargar los catalogos auxiliares.';
      }
    });
  }

  loadItems(): void {
    const currentConfig = this.config;

    if (!currentConfig) {
      return;
    }

    this.loading = true;
    this.errorMessage = '';

    this.catalogCrudService.list<Record<string, unknown>>(currentConfig.endpoint).subscribe({
      next: items => {
        this.items = items;
        this.loading = false;
        this.applySearch();
      },
      error: () => {
        this.loading = false;
        this.errorMessage = `No se pudo cargar ${currentConfig.title.toLowerCase()}.`;
      }
    });
  }

  applySearch(): void {
    const term = this.searchTerm.trim().toLowerCase();

    this.filteredItems = !term
      ? [...this.items]
      : this.items.filter(item =>
          this.config?.searchKeys.some(key => String(item[key] ?? '').toLowerCase().includes(term))
        );

    this.tableRows = this.filteredItems.map(item => ({
      ...this.config?.toTableRow(item, this.lookupData),
      _entity: item
    }));
  }

  openDialog(entity?: Record<string, unknown>): void {
    if (!this.config) {
      return;
    }

    const dialogRef = this.dialog.open(CatalogFormDialogPage, {
      width: '780px',
      data: {
        config: this.config,
        entity: entity ?? null,
        lookupData: this.lookupData
      }
    });

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

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

  deleteItem(item: Record<string, unknown>): void {
    if (!this.config) {
      return;
    }

    const itemId = Number(item['id']);
    if (!itemId) {
      return;
    }

    if (typeof window === 'undefined') {
      return;
    }

    const itemName = String(item['name'] ?? this.config.singular);
    if (!window.confirm(`Eliminar ${this.config.singular} "${itemName}"?`)) {
      return;
    }

    this.catalogCrudService.delete(this.config.endpoint, itemId).subscribe({
      next: () => {
        this.message = { type: 'success', text: 'Registro eliminado correctamente.' };
        this.loadItems();
      },
      error: () => {
        this.message = { type: 'error', text: 'No se pudo eliminar el registro.' };
      }
    });
  }

  hasData(): boolean {
    return this.tableRows.length > 0;
  }
}
