import { Injectable } from '@angular/core';
import { firstValueFrom } from 'rxjs';

import { environment } from '../../../environments/environment';
import { BaseApiService } from './base-api.service';

export interface UpdatePurchaseCustomerPayload {
  dni: string;
  telefono: string;
  nombre_apellido: string;
  email: string;
}

export type StartCheckoutPayload =
  | {
      cart_id: number;
    }
  | {
      direct_item: {
        catalog_item_id: number;
        variant_id: number | null;
        cantidad: number;
      };
    };

export interface PurchaseStatusResponse {
  status: string | null;
}

export interface PurchaseSummaryResponse extends PurchaseStatusResponse {
  id: number;
  created_at: string | null;
  total: string;
}

export interface PurchaseDetailAttributeResponse {
  name: string;
  value: string | number | boolean | null;
}

export interface PurchaseDetailItemResponse {
  id: number;
  quantity: number;
  unit_price: string;
  line_total: string;
  source_catalog_item_id: number | null;
  source_variant_id: number | null;
  item_details: {
    nombre: string;
    descripcion: string | null;
    slug: string;
    imagen: string | null;
    attributes: PurchaseDetailAttributeResponse[];
  };
}

export interface PurchaseDetailResponse extends PurchaseStatusResponse {
  id: number;
  cart_id: number | null;
  tenant_codigo: string;
  user_id: number;
  created_at: string | null;
  payment_method: string | null;
  dni: string | null;
  transfer_payer_dni: string | null;
  telefono: string | null;
  nombre_apellido: string | null;
  email: string | null;
  items_source: 'purchase';
  items: PurchaseDetailItemResponse[];
  tickets_count?: number;
  has_generated_tickets?: boolean;
  subtotal: string;
  total: string;
}

@Injectable({
  providedIn: 'root',
})
export class CheckoutService extends BaseApiService {
  async startCheckout(
    tenantCode: string,
    payload: StartCheckoutPayload,
  ): Promise<PurchaseDetailResponse> {
    const response = await firstValueFrom(
      this.http.post<{ data?: PurchaseDetailResponse } | PurchaseDetailResponse>(
        `${environment.url}tenants/${tenantCode}/compras/start-checkout`,
        payload,
      ),
    );

    const purchase = this.extractResponseData<PurchaseDetailResponse>(response);

    if (!purchase?.id) {
      throw new Error('Error al crear la compra.');
    }

    return purchase;
  }

  async generatePaymentIntent(
    tenantCode: string,
    purchaseId: number,
    method: 'qr' | 'transfer' | 'telepagos',
    payerDni?: string,
  ): Promise<any> {
    const payload: any = { method };
    if (payerDni) {
      payload.transfer_payer_dni = payerDni;
    }
    const response = await firstValueFrom(
      this.http.post<any>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}/payment-intent`,
        payload,
      ),
    );
    if (!response) {
      throw new Error('Error al generar la intención de pago.');
    }
    return response;
  }

  async updateCustomerData(
    tenantCode: string,
    purchaseId: number,
    payload: UpdatePurchaseCustomerPayload,
  ): Promise<PurchaseDetailResponse> {
    const response = await firstValueFrom(
      this.http.patch<{ data?: PurchaseDetailResponse } | PurchaseDetailResponse>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}/customer-data`,
        payload,
      ),
    );

    const purchase = this.extractResponseData<PurchaseDetailResponse>(response);
    if (!purchase) {
      throw new Error('Error al actualizar los datos de la compra.');
    }

    return purchase;
  }

  async updateItemQuantity(
    tenantCode: string,
    purchaseId: number,
    itemId: number,
    quantity: number,
  ): Promise<PurchaseDetailResponse> {
    const response = await firstValueFrom(
      this.http.patch<{ data?: PurchaseDetailResponse } | PurchaseDetailResponse>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}/items/${itemId}`,
        { quantity },
      ),
    );

    const purchase = this.extractResponseData<PurchaseDetailResponse>(response);
    if (!purchase) {
      throw new Error('Error al actualizar la cantidad del producto.');
    }

    return purchase;
  }

  async prepareItemEditing(
    tenantCode: string,
    purchaseId: number,
  ): Promise<PurchaseDetailResponse> {
    const response = await firstValueFrom(
      this.http.post<{ data?: PurchaseDetailResponse } | PurchaseDetailResponse>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}/edit-items`,
        {},
      ),
    );

    const purchase = this.extractResponseData<PurchaseDetailResponse>(response);
    if (!purchase) {
      throw new Error('Error al preparar la compra para editarla.');
    }

    return purchase;
  }

  async completePurchase(
    tenantCode: string,
    purchaseId: number,
  ): Promise<PurchaseStatusResponse> {
    const response = await firstValueFrom(
      this.http.post<{ data?: PurchaseStatusResponse } | PurchaseStatusResponse>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}/complete`,
        {},
      ),
    );

    const purchase = this.extractResponseData<PurchaseStatusResponse>(response);

    if (!purchase) {
      throw new Error('Error al finalizar la compra.');
    }

    return {
      status: purchase.status ?? null,
    };
  }

  async submitPurchaseForReview(
    tenantCode: string,
    purchaseId: number,
  ): Promise<PurchaseStatusResponse> {
    const response = await firstValueFrom(
      this.http.post<{ data?: PurchaseStatusResponse } | PurchaseStatusResponse>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}/review`,
        {},
      ),
    );

    const purchase = this.extractResponseData<PurchaseStatusResponse>(response);
    if (!purchase) {
      throw new Error('Error al enviar la compra a revisi\u00f3n.');
    }

    return { status: purchase.status ?? null };
  }

  async cancelPurchase(
    tenantCode: string,
    purchaseId: number,
  ): Promise<PurchaseStatusResponse> {
    const response = await firstValueFrom(
      this.http.post<{ data?: PurchaseStatusResponse } | PurchaseStatusResponse>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}/cancel`,
        {},
      ),
    );

    const purchase = this.extractResponseData<PurchaseStatusResponse>(response);
    if (!purchase) {
      throw new Error('Error al cancelar la compra.');
    }

    return { status: purchase.status ?? null };
  }

  async getPurchases(
    tenantCode: string,
    status?: string,
  ): Promise<{ data: PurchaseSummaryResponse[] }> {
    let url = `${environment.url}tenants/${tenantCode}/compras`;
    if (status) {
      url += `?status=${status}`;
    }
    const response = await firstValueFrom(
      this.http.get<{ data: PurchaseSummaryResponse[] }>(url),
    );
    if (!response) {
      throw new Error('Error al obtener las compras.');
    }
    return response;
  }

  async getPurchase(
    tenantCode: string,
    purchaseId: string | number,
  ): Promise<PurchaseDetailResponse> {
    const response = await firstValueFrom(
      this.http.get<{ data?: PurchaseDetailResponse } | PurchaseDetailResponse>(
        `${environment.url}tenants/${tenantCode}/compras/${purchaseId}`,
      ),
    );

    const purchase = this.extractResponseData<PurchaseDetailResponse>(response);

    if (!purchase) {
      throw new Error('Error al obtener la compra.');
    }

    return purchase;
  }

  private extractResponseData<T>(response: T | { data?: T } | null | undefined): T | null {
    if (!response) {
      return null;
    }

    if (typeof response === 'object' && 'data' in response && response.data) {
      return response.data;
    }

    return response as T;
  }
}
