import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { map, Observable } from 'rxjs';
import { environment } from '../../environments/environment';
import { Expense } from '../models/expense.model';
import { ExpenseCategory } from '../models/expense-category.model';
import { ExpenseCenter } from '../models/expense-center.model';
import { ExpenseSummary } from '../models/expense-summary.model';
import { ApiCollectionResponse } from '../models/api-response.model';
import { extractCollectionData } from '../utils/api-response.util';

export interface ExpenseFilters {
  from?: string;
  to?: string;
  expenseCenterId?: string;
  categoryId?: string;
  status?: string;
}

@Injectable({
  providedIn: 'root'
})
export class ExpenseService {
  private apiUrl = `${environment.apiBaseUrl}/expenses`;
  private categoriesUrl = `${environment.apiBaseUrl}/expenses/categories`;
  private centersUrl = `${environment.apiBaseUrl}/expenses/centers`;

  constructor(private http: HttpClient) {}

  getAll(filters?: ExpenseFilters): Observable<Expense[]> {
    return this.http
      .get<Expense[] | ApiCollectionResponse<Expense>>(this.apiUrl, {
        params: this.buildParams(filters)
      })
      .pipe(map(response => extractCollectionData(response)));
  }

  getById(id: number): Observable<Expense> {
    return this.http.get<Expense>(`${this.apiUrl}/${id}`);
  }

  create(expense: Expense): Observable<Expense> {
    return this.http.post<Expense>(this.apiUrl, expense);
  }

  update(id: number, expense: Expense): Observable<Expense> {
    return this.http.put<Expense>(`${this.apiUrl}/${id}`, expense);
  }

  delete(id: number): Observable<void> {
    return this.http.delete<void>(`${this.apiUrl}/${id}`);
  }

  getSummary(filters?: ExpenseFilters): Observable<ExpenseSummary> {
    return this.http.get<ExpenseSummary>(`${this.apiUrl}/summary`, {
      params: this.buildParams(filters)
    });
  }

  getCategories(): Observable<ExpenseCategory[]> {
    return this.http
      .get<ExpenseCategory[] | ApiCollectionResponse<ExpenseCategory>>(this.categoriesUrl)
      .pipe(map(response => extractCollectionData(response)));
  }

  createCategory(category: ExpenseCategory): Observable<ExpenseCategory> {
    return this.http.post<ExpenseCategory>(this.categoriesUrl, category);
  }

  getCategoryById(id: number): Observable<ExpenseCategory> {
    return this.http.get<ExpenseCategory>(`${this.categoriesUrl}/${id}`);
  }

  updateCategory(id: number, category: ExpenseCategory): Observable<ExpenseCategory> {
    return this.http.put<ExpenseCategory>(`${this.categoriesUrl}/${id}`, category);
  }

  deleteCategory(id: number): Observable<void> {
    return this.http.delete<void>(`${this.categoriesUrl}/${id}`);
  }

  getCenters(): Observable<ExpenseCenter[]> {
    return this.http
      .get<ExpenseCenter[] | ApiCollectionResponse<ExpenseCenter>>(this.centersUrl)
      .pipe(map(response => extractCollectionData(response)));
  }

  createCenter(center: ExpenseCenter): Observable<ExpenseCenter> {
    return this.http.post<ExpenseCenter>(this.centersUrl, center);
  }

  getCenterById(id: number): Observable<ExpenseCenter> {
    return this.http.get<ExpenseCenter>(`${this.centersUrl}/${id}`);
  }

  updateCenter(id: number, center: ExpenseCenter): Observable<ExpenseCenter> {
    return this.http.put<ExpenseCenter>(`${this.centersUrl}/${id}`, center);
  }

  deleteCenter(id: number): Observable<void> {
    return this.http.delete<void>(`${this.centersUrl}/${id}`);
  }

  private buildParams(filters?: ExpenseFilters): HttpParams {
    let params = new HttpParams();

    if (!filters) {
      return params;
    }

    Object.entries(filters).forEach(([key, value]) => {
      if (value !== null && value !== undefined && value !== '') {
        params = params.set(key, String(value));
      }
    });

    return params;
  }
}
