import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable, forkJoin, of } from 'rxjs';
import { switchMap, map } from 'rxjs/operators';
import { environment } from '../../../environments/environment';
import { ApiResponse, PaginatedResponse } from '../models/api.model';
import {
  SalesInvoice,
  CreateSalesInvoice,
  UpdateSalesInvoice,
} from '../models/sales-invoice.model';
import { CreateSalesPayment, SalesPayment } from '../models/sales-payment.model';

@Injectable({ providedIn: 'root' })
export class SalesInvoiceService {
  private http = inject(HttpClient);
  private apiUrl = `${environment.apiUrl}/sales/invoices`;

  private buildParams(filters?: Record<string, any>): HttpParams {
    let params = new HttpParams();
    if (filters) {
      Object.entries(filters).forEach(([key, value]) => {
        if (value != null && value !== '') {
          params = params.set(key, String(value));
        }
      });
    }
    return params;
  }

  list(page = 1, perPage = 100, filters?: Record<string, any>): Observable<PaginatedResponse<SalesInvoice>> {
    let params = this.buildParams(filters)
      .set('page', page)
      .set('per_page', perPage);
    return this.http.get<PaginatedResponse<SalesInvoice>>(this.apiUrl, { params });
  }

  /** Fetch ALL pages in parallel and return combined result */
  listAll(): Observable<PaginatedResponse<SalesInvoice>> {
    return this.list(1, 200).pipe(
      switchMap((firstPage) => {
        const lastPage = firstPage.meta.last_page;
        if (lastPage <= 1) {
          return of(firstPage);
        }
        const requests: Observable<PaginatedResponse<SalesInvoice>>[] = [];
        for (let p = 2; p <= lastPage; p++) {
          requests.push(this.list(p, 200));
        }
        return forkJoin(requests).pipe(
          map((responses) => {
            const allData = [
              ...firstPage.data,
              ...responses.flatMap((r) => r.data),
            ];
            return {
              data: allData,
              links: firstPage.links,
              meta: { ...firstPage.meta, current_page: 1, last_page: 1, per_page: allData.length, to: allData.length, total: allData.length },
            } as PaginatedResponse<SalesInvoice>;
          })
        );
      })
    );
  }

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

  create(data: CreateSalesInvoice): Observable<ApiResponse<SalesInvoice>> {
    return this.http.post<ApiResponse<SalesInvoice>>(this.apiUrl, data);
  }

  update(id: number, data: UpdateSalesInvoice): Observable<ApiResponse<SalesInvoice>> {
    return this.http.put<ApiResponse<SalesInvoice>>(`${this.apiUrl}/${id}`, data);
  }

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

  submitApproval(id: number): Observable<ApiResponse<SalesInvoice>> {
    return this.http.post<ApiResponse<SalesInvoice>>(`${this.apiUrl}/${id}/submit-approval`, {});
  }

  approve(id: number): Observable<ApiResponse<SalesInvoice>> {
    return this.http.post<ApiResponse<SalesInvoice>>(`${this.apiUrl}/${id}/approve`, {});
  }

  reject(id: number, data?: { reason: string }): Observable<ApiResponse<SalesInvoice>> {
    return this.http.post<ApiResponse<SalesInvoice>>(`${this.apiUrl}/${id}/reject`, data || {});
  }

  post(id: number): Observable<ApiResponse<SalesInvoice>> {
    return this.http.post<ApiResponse<SalesInvoice>>(`${this.apiUrl}/${id}/post`, {});
  }

  cancel(id: number): Observable<ApiResponse<SalesInvoice>> {
    return this.http.post<ApiResponse<SalesInvoice>>(`${this.apiUrl}/${id}/cancel`, {});
  }

  recordPayment(id: number, data: CreateSalesPayment): Observable<ApiResponse<SalesPayment>> {
    return this.http.post<ApiResponse<SalesPayment>>(`${environment.apiUrl}/sales/payments`, data);
  }

  postPayment(paymentId: number): Observable<ApiResponse<SalesPayment>> {
    return this.http.post<ApiResponse<SalesPayment>>(`${environment.apiUrl}/sales/payments/${paymentId}/post`, {});
  }

  getPayments(id: number): Observable<{ data: SalesPayment[] }> {
    return this.http.get<{ data: SalesPayment[] }>(`${this.apiUrl}/${id}/payments`);
  }

  getPaymentSchedule(id: number): Observable<{ data: any[] }> {
    return this.http.get<{ data: any[] }>(`${this.apiUrl}/${id}/payment-schedule`);
  }

  getPdf(id: number): Observable<Blob> {
    return this.http.get(`${this.apiUrl}/${id}/pdf`, { responseType: 'blob' });
  }

  duplicate(id: number): Observable<ApiResponse<SalesInvoice>> {
    return this.http.post<ApiResponse<SalesInvoice>>(`${this.apiUrl}/${id}/duplicate`, {});
  }
}
