import { apiEndpoints, API_CONFIG, QUERY_KEYS, HTTP_STATUS, createHttpError } from "@/lib/api-config";
import type {
  Account,
  Transaction,
  Transfer,
  BalanceDetails,
  BankingStats,
  AccountStatement,
  AccountListResponse,
  TransactionListResponse,
  TransferListResponse,
  AccountCreateData,
  AccountUpdateData,
  TransactionCreateData,
  TransferCreateData,
  DepositData,
  WithdrawalData,
  AccountFilters,
  TransactionFilters,
  TransferFilters,
  BulkAccountAction,
  BulkTransactionAction,
} from "@/types/banking";

// Fonction utilitaire pour gérer les erreurs API
const handleApiError = async (response: Response): Promise<never> => {
  let errorData: { detail?: string; message?: string; [key: string]: unknown };
  try {
    errorData = await response.json();
  } catch {
    errorData = { message: "Erreur de communication avec le serveur" };
  }

  const errorMessage = errorData.detail ?? errorData.message ?? `Erreur HTTP ${response.status}`;

  throw createHttpError(response.status, errorMessage, errorData);
};

// Fonction utilitaire pour construire les paramètres de requête
const buildSearchParams = (filters: Record<string, string | number | undefined>): string => {
  const params = new URLSearchParams();
  Object.entries(filters).forEach(([key, value]) => {
    if (value !== undefined && value !== "") {
      params.append(key, String(value));
    }
  });
  return params.toString();
};

// Service principal Banking
export class BankingService {
  // ========================
  // ACCOUNTS ENDPOINTS
  // ========================

  /**
   * Récupère la liste des comptes avec filtres optionnels
   */
  static async getAccounts(filters: AccountFilters = {}): Promise<AccountListResponse> {
    const queryString = buildSearchParams(filters);
    const baseUrl = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.list}`;
    const url = queryString ? `${baseUrl}?${queryString}` : baseUrl;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Récupère les détails d'un compte
   */
  static async getAccount(id: number): Promise<Account> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.detail(id)}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Crée un nouveau compte
   */
  static async createAccount(data: AccountCreateData): Promise<Account> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.create}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Crée un compte pour un client spécifique
   */
  static async createAccountForClient(data: AccountCreateData): Promise<Account> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.createForClient}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Met à jour un compte
   */
  static async updateAccount(id: number, data: AccountUpdateData): Promise<Account> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.update(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "PATCH",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Supprime un compte
   */
  static async deleteAccount(id: number): Promise<void> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.delete(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "DELETE",
    });

    if (!response.ok && response.status !== HTTP_STATUS.NO_CONTENT) {
      await handleApiError(response);
    }
  }

  /**
   * Gèle un compte
   */
  static async freezeAccount(id: number, reason?: string): Promise<Account> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.freeze(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify({ reason }),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Dégèle un compte
   */
  static async unfreezeAccount(id: number, reason?: string): Promise<Account> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.unfreeze(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify({ reason }),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Récupère le solde d'un compte
   */
  static async getAccountBalance(id: number): Promise<BalanceDetails> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.balance(id)}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Récupère le relevé de compte
   */
  static async getAccountStatement(
    id: number,
    fromDate: string,
    toDate: string,
  ): Promise<AccountStatement> {
    const params = buildSearchParams({ from_date: fromDate, to_date: toDate });
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.statement(id)}?${params}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Actions en lot sur les comptes
   */
  static async bulkAccountActions(
    action: BulkAccountAction,
  ): Promise<{ success: boolean; results: Account[] }> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.accounts.bulkActions}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(action),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  // ========================
  // TRANSACTIONS ENDPOINTS
  // ========================

  /**
   * Récupère la liste des transactions avec filtres optionnels
   */
  static async getTransactions(filters: TransactionFilters = {}): Promise<TransactionListResponse> {
    const queryString = buildSearchParams(filters);
    const baseUrl = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.list}`;
    const url = queryString ? `${baseUrl}?${queryString}` : baseUrl;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Récupère les détails d'une transaction
   */
  static async getTransaction(id: number): Promise<Transaction> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.detail(id)}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Crée une nouvelle transaction
   */
  static async createTransaction(data: TransactionCreateData): Promise<Transaction> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.create}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Crée une transaction pour un client spécifique
   */
  static async createTransactionForClient(data: TransactionCreateData): Promise<Transaction> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.createForClient}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Effectue un dépôt
   */
  static async deposit(data: DepositData): Promise<Transaction> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.deposit}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Effectue un retrait
   */
  static async withdrawal(data: WithdrawalData): Promise<Transaction> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.withdrawal}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Annule une transaction
   */
  static async cancelTransaction(id: number, reason?: string): Promise<Transaction> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.cancel(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify({ reason }),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Inverse une transaction
   */
  static async reverseTransaction(id: number, reason?: string): Promise<Transaction> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.reverse(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify({ reason }),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Actions en lot sur les transactions
   */
  static async bulkTransactionActions(
    action: BulkTransactionAction,
  ): Promise<{ success: boolean; results: Transaction[] }> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transactions.bulkActions}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(action),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  // ========================
  // TRANSFERS ENDPOINTS
  // ========================

  /**
   * Récupère la liste des transferts avec filtres optionnels
   */
  static async getTransfers(filters: TransferFilters = {}): Promise<TransferListResponse> {
    const queryString = buildSearchParams(filters);
    const baseUrl = `${API_CONFIG.baseURL}${apiEndpoints.banking.transfers.list}`;
    const url = queryString ? `${baseUrl}?${queryString}` : baseUrl;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Récupère les détails d'un transfert
   */
  static async getTransfer(id: number): Promise<Transfer> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transfers.detail(id)}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Crée un nouveau transfert
   */
  static async createTransfer(data: TransferCreateData): Promise<Transfer> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transfers.create}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify(data),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Annule un transfert
   */
  static async cancelTransfer(id: number, reason?: string): Promise<Transfer> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transfers.cancel(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
      body: JSON.stringify({ reason }),
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Traite un transfert
   */
  static async processTransfer(id: number): Promise<Transfer> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.transfers.process(id)}`;

    const response = await fetch(url, {
      headers: API_CONFIG.defaultHeaders,
      method: "POST",
    });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  // ========================
  // STATS & REPORTS ENDPOINTS
  // ========================

  /**
   * Récupère les statistiques Banking
   */
  static async getBankingStats(): Promise<BankingStats> {
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.stats}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.json();
  }

  /**
   * Génère un rapport de relevé de compte
   */
  static async generateAccountStatementReport(
    accountId: number,
    fromDate: string,
    toDate: string,
  ): Promise<Blob> {
    const params = buildSearchParams({
      account_id: accountId,
      from_date: fromDate,
      to_date: toDate,
    });
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.reports.accountStatement}?${params}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.blob();
  }

  /**
   * Génère un rapport de résumé des transactions
   */
  static async generateTransactionSummaryReport(filters: TransactionFilters): Promise<Blob> {
    const params = buildSearchParams(filters);
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.reports.transactionSummary}?${params}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.blob();
  }

  /**
   * Génère un rapport des transferts
   */
  static async generateTransferReport(filters: TransferFilters): Promise<Blob> {
    const params = buildSearchParams(filters);
    const url = `${API_CONFIG.baseURL}${apiEndpoints.banking.reports.transferReport}?${params}`;

    const response = await fetch(url, { headers: API_CONFIG.defaultHeaders });

    if (!response.ok) {
      await handleApiError(response);
    }

    return response.blob();
  }
}

// Export des clés de requête pour TanStack Query
export const bankingQueryKeys = QUERY_KEYS.banking;

// Export d'une instance par défaut du service
export const bankingService = new BankingService();
