import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, switchMap, forkJoin, of, catchError } from 'rxjs';
import { environment } from '../../../../environments/environment';

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

  createInvoice(data: any): Observable<any> {
    return this.http.post(`${this.base}/invoices`, {
      ...data,
      source: 'pos',
      auto_post: true,
    });
  }

  approveInvoice(id: number): Observable<any> {
    return this.http.post(`${this.base}/invoices/${id}/approve`, {});
  }

  postInvoice(id: number): Observable<any> {
    return this.http.post(`${this.base}/invoices/${id}/post`, {});
  }

  postPayment(id: number): Observable<any> {
    return this.http.post(`${this.base}/payments/${id}/post`, {});
  }

  /**
   * Full POS sale: create invoice → approve → post → create payments → post payments
   */
  processSale(invoiceData: any, paymentLines: { method: string; amount: number; reference?: string }[], receivingAccountId?: number): Observable<any> {
    const today = new Date();
    const date = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;

    return this.createInvoice(invoiceData).pipe(
      switchMap((invoiceRes) => {
        const invoice = invoiceRes.data;
        return this.approveInvoice(invoice.id).pipe(
          switchMap(() => this.postInvoice(invoice.id)),
          // Auto-approve inventory issue created by backend
          switchMap(() => this.approveInventoryIssue(invoice.id)),
          // Re-fetch invoice to get accurate balance_due from backend
          switchMap(() => this.http.get<any>(`${this.base}/invoices/${invoice.id}`)),
          switchMap((freshRes) => {
            const freshInvoice = freshRes.data;
            const balanceDue = parseFloat(freshInvoice.balance_due || freshInvoice.total || '0');

            // Scale payment lines proportionally to match backend's balance_due
            const frontendTotal = paymentLines.reduce((s, l) => s + l.amount, 0);
            const ratio = frontendTotal > 0 ? balanceDue / frontendTotal : 1;

            const adjustedLines = paymentLines.map((line) => ({
              ...line,
              amount: Math.round(line.amount * ratio * 100) / 100,
            }));

            // Create one payment per line
            const paymentRequests = adjustedLines
              .filter((line) => line.amount > 0)
              .map((line) =>
                this.http.post<any>(`${this.base}/payments`, {
                  invoice_id: freshInvoice.id,
                  date,
                  amount: line.amount,
                  payment_method: line.method,
                  receiving_account_id: receivingAccountId || 1,
                  reference: line.reference || null,
                })
              );

            if (paymentRequests.length === 0) {
              return of({ invoice: freshInvoice, payments: [] });
            }

            // Create all payments, then post them all
            return forkJoin(paymentRequests).pipe(
              switchMap((paymentResults) => {
                const payments = paymentResults.map((r: any) => r.data);
                const postRequests = payments.map((p: any) => this.postPayment(p.id));
                return forkJoin(postRequests).pipe(
                  switchMap(() => of({ invoice: freshInvoice, payments }))
                );
              })
            );
          })
        );
      })
    );
  }

  /**
   * Find and approve the inventory issue auto-created by the backend for this invoice
   */
  private approveInventoryIssue(invoiceId: number): Observable<any> {
    const inventoryBase = `${environment.apiUrl}/inventory`;
    return this.http
      .get<any>(`${inventoryBase}/issues`, {
        params: { reference_type: 'sale', reference_id: String(invoiceId), status: 'draft' },
      })
      .pipe(
        switchMap((res) => {
          const issues = res.data || [];
          if (issues.length === 0) return of(null);
          const approveRequests = issues.map((issue: any) =>
            this.http.post(`${inventoryBase}/issues/${issue.id}/approve`, {})
          );
          return forkJoin(approveRequests);
        }),
        catchError(() => of(null)) // Don't block sale if issue approval fails
      );
  }

  createPayment(data: any): Observable<any> {
    return this.http.post(`${this.base}/payments`, data);
  }

  createReturn(data: any): Observable<any> {
    return this.http.post(`${this.base}/returns`, data);
  }

  getInvoice(id: number): Observable<any> {
    return this.http.get(`${this.base}/invoices/${id}`);
  }

  searchInvoice(query: string): Observable<any> {
    return this.http.get(`${this.base}/invoices`, { params: { search: query } });
  }
}
