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 { ExpenseCategory } from '../../models/expense-category.model';
import { ExpenseCenter } from '../../models/expense-center.model';
import { ExpenseSummary, ExpenseSummaryCategoryItem } from '../../models/expense-summary.model';
import { Expense, ExpenseStatus } from '../../models/expense.model';
import { User } from '../../models/user.model';
import { BrowserStorageService } from '../../services/browser-storage.service';
import { ExpenseFilters, ExpenseService } from '../../services/expense.service';
import { UserService } from '../../services/user.service';
import { PageTopbarComponent } from '../../shared/components/page-topbar/page-topbar.component';
import { ExpenseCategoryModalPage } from './expense-category-modal/expense-category-modal.page';
import { ExpensePage } from './expense/expense.page';

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

@Component({
  selector: 'app-expenses-dashboard',
  standalone: true,
  imports: [CommonModule, FormsModule, SidebarComponent, PageTopbarComponent],
  templateUrl: './expenses-dashboard.page.html',
  styleUrls: ['./expenses-dashboard.page.scss']
})
export class ExpensesDashboardPage implements OnInit {
  expenses: Expense[] = [];
  summary: ExpenseSummary | null = null;
  categories: ExpenseCategory[] = [];
  expenseCenters: ExpenseCenter[] = [];
  users: User[] = [];

  filters: ExpenseFilters = {
    from: '',
    to: '',
    expenseCenterId: '',
    categoryId: '',
    status: ''
  };

  loading = true;
  summaryLoading = true;
  categoriesLoading = true;

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

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

  private readonly filterStorageKey = 'expenses.filters';

  constructor(
    private expenseService: ExpenseService,
    private userService: UserService,
    private storage: BrowserStorageService,
    private dialog: MatDialog
  ) {}

  ngOnInit(): void {
    const storedFilters = this.storage.getObject<Partial<ExpenseFilters> & { branchId?: string }>(
      this.filterStorageKey,
      {}
    );

    this.filters = {
      from: storedFilters.from ?? '',
      to: storedFilters.to ?? '',
      expenseCenterId: storedFilters.expenseCenterId ?? '',
      categoryId: storedFilters.categoryId ?? '',
      status: storedFilters.status ?? ''
    };

    this.loadInitialData();
  }

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

    forkJoin({
      categories: this.expenseService.getCategories(),
      expenseCenters: this.expenseService.getCenters(),
      users: this.userService.getAllUsers()
    }).subscribe({
      next: ({ categories, expenseCenters, users }) => {
        this.categories = categories;
        this.expenseCenters = expenseCenters;
        this.users = users;
        this.categoriesLoading = false;
        this.loadExpenses();
        this.loadSummary();
      },
      error: () => {
        this.loading = false;
        this.categoriesLoading = false;
        this.summaryLoading = false;
        this.errorMessage = 'No se pudieron cargar los catalogos de gastos.';
        this.categoriesError = this.errorMessage;
      }
    });
  }

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

    this.expenseService.getAll(this.filters).subscribe({
      next: expenses => {
        this.expenses = expenses;
        this.loading = false;
      },
      error: () => {
        this.loading = false;
        this.errorMessage = 'No se pudieron cargar los gastos.';
      }
    });
  }

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

    this.expenseService.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 gastos.';
      }
    });
  }

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

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

  openExpenseModal(expense?: Expense): void {
    const dialogRef = this.dialog.open(ExpensePage, {
      width: '860px',
      data: {
        expense: expense ?? null,
        categories: this.categories,
        expenseCenters: this.expenseCenters,
        users: this.users
      }
    });

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

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

  openCategoryModal(category?: ExpenseCategory): void {
    const dialogRef = this.dialog.open(ExpenseCategoryModalPage, {
      width: '640px',
      data: category ?? null
    });

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

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

  deleteExpense(expense: Expense): void {
    if (!expense.id) {
      return;
    }

    if (!this.storage.isBrowser() || !window.confirm(`Eliminar el gasto "${expense.description}"?`)) {
      return;
    }

    this.expenseService.delete(expense.id).subscribe({
      next: () => {
        this.message = { type: 'success', text: 'Gasto eliminado correctamente.' };
        this.loadExpenses();
        this.loadSummary();
      },
      error: () => {
        this.message = { type: 'error', text: 'No se pudo eliminar el gasto.' };
      }
    });
  }

  deleteCategory(category: ExpenseCategory): void {
    if (!category.id) {
      return;
    }

    if (!this.storage.isBrowser() || !window.confirm(`Eliminar la categoria "${category.name}"?`)) {
      return;
    }

    this.expenseService.deleteCategory(category.id).subscribe({
      next: () => {
        this.message = { type: 'success', text: 'Categoria eliminada correctamente.' };
        this.refreshCategories();
      },
      error: () => {
        this.message = { type: 'error', text: 'No se pudo eliminar la categoria.' };
      }
    });
  }

  getExpenseCenterName(expenseCenterId?: number | null): string {
    if (!expenseCenterId) {
      return 'Sin centro de gasto';
    }

    return this.expenseCenters.find(center => center.id === expenseCenterId)?.name ?? `Centro #${expenseCenterId}`;
  }

  getCategoryName(categoryId: number): string {
    return this.categories.find(category => category.id === categoryId)?.name ?? `Categoria #${categoryId}`;
  }

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

  getStatusLabel(status: ExpenseStatus): string {
    switch (status) {
      case 'PAID':
        return 'Pagado';
      case 'CANCELLED':
        return 'Cancelado';
      default:
        return 'Pendiente';
    }
  }

  getSummaryCategoryName(item: ExpenseSummaryCategoryItem): string {
    return item.categoryName ?? item.name ?? 'Sin categoria';
  }

  getSummaryCategoryAmount(item: ExpenseSummaryCategoryItem): number {
    return Number(item.totalAmount ?? item.amount ?? 0);
  }

  hasExpenses(): boolean {
    return this.expenses.length > 0;
  }

  private refreshCategories(): void {
    this.categoriesLoading = true;
    this.categoriesError = '';

    this.expenseService.getCategories().subscribe({
      next: categories => {
        this.categories = categories;
        this.categoriesLoading = false;
        this.loadExpenses();
        this.loadSummary();
      },
      error: () => {
        this.categoriesLoading = false;
        this.categoriesError = 'No se pudieron cargar las categorias de gastos.';
      }
    });
  }
}
