import axios, { AxiosInstance } from 'axios';

export interface Payment {
  id: string;
  amount: number;
  currency: string;
  status: 'pending' | 'completed' | 'failed' | 'refunded';
  paymentMethod: string;
  createdAt: string;
  description?: string;
}

export interface LedgerEntry {
  id: string;
  accountId: string;
  amount: number;
  currency: string;
  type: 'debit' | 'credit';
  description: string;
  timestamp: string;
  reference?: string;
}

export interface BasketAllocation {
  symbol: string;
  targetWeightBps: number;
  routeHint?: string;
}

export interface BasketMandate {
  id: string;
  clientId: string;
  mandateName: string;
  chain138VaultAddress: string;
  baseAssetSymbol: string;
  status: 'draft' | 'active' | 'rebalancing' | 'closed';
  allocations: BasketAllocation[];
  createdAt: string;
  updatedAt: string;
}

export interface BtcDeposit {
  id: string;
  clientId: string;
  basketId: string;
  chain138VaultAddress: string;
  depositAddress: string;
  expectedAmountSats?: number;
  confirmationsRequired: number;
  currentConfirmations: number;
  status:
    | 'instruction_created'
    | 'pending_confirmations'
    | 'confirmed'
    | 'minted'
    | 'frozen';
  observedTxId?: string;
  freezeReason?: string;
  createdAt: string;
  updatedAt: string;
}

export interface Holding {
  clientId: string;
  basketId: string;
  symbol: string;
  allocationWeightBps: number;
  bookValueSats: number;
  status: 'pending_funding' | 'funded';
  updatedAt: string;
}

export interface Rebalance {
  id: string;
  clientId: string;
  basketId: string;
  sourceSymbol: string;
  targetSymbols: string[];
  reason: string;
  status: 'planned' | 'queued' | 'executed' | 'failed';
  createdAt: string;
  updatedAt: string;
}

export interface BridgeWithdrawal {
  id: string;
  clientId: string;
  basketId: string;
  sourceSymbol: string;
  destinationSymbol: string;
  destinationChainId: number;
  destinationAddress: string;
  amount: string;
  status: 'pending' | 'approved' | 'submitted' | 'failed';
  createdAt: string;
  updatedAt: string;
}

export class FinanceClient {
  protected client: AxiosInstance;

  constructor(baseURL?: string) {
    const apiBaseURL =
      baseURL ||
      (typeof window !== 'undefined'
        ? process.env.NEXT_PUBLIC_FINANCE_SERVICE_URL || 'http://localhost:4003'
        : 'http://localhost:4003');

    this.client = axios.create({
      baseURL: apiBaseURL,
      headers: {
        'Content-Type': 'application/json',
      },
    });

    this.client.interceptors.request.use(
      (config) => {
        const token = this.getAuthToken();
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
      (error) => Promise.reject(error),
    );
  }

  private getAuthToken(): string | null {
    if (typeof window === 'undefined') return null;
    return localStorage.getItem('auth_token');
  }

  setAuthToken(token: string): void {
    if (typeof window !== 'undefined') {
      localStorage.setItem('auth_token', token);
    }
  }

  clearAuthToken(): void {
    if (typeof window !== 'undefined') {
      localStorage.removeItem('auth_token');
    }
  }

  async createPayment(data: {
    amount: number;
    currency: string;
    paymentMethod: string;
    description?: string;
  }): Promise<Payment> {
    const response = await this.client.post<{ payment: Payment }>('/api/v1/payments', data);
    return response.data.payment;
  }

  async getPayment(paymentId: string): Promise<Payment> {
    const response = await this.client.get<Payment>(`/api/v1/payments/${paymentId}`);
    return response.data;
  }

  async listPayments(filters?: {
    status?: string;
    page?: number;
    pageSize?: number;
  }): Promise<{ payments: Payment[]; total: number }> {
    const response = await this.client.get<{ payments: Payment[]; total: number }>('/api/v1/payments', {
      params: filters,
    });
    return response.data;
  }

  async getLedgerEntries(filters?: {
    accountId?: string;
    type?: 'debit' | 'credit';
    startDate?: string;
    endDate?: string;
    page?: number;
    pageSize?: number;
  }): Promise<{ entries: LedgerEntry[]; total: number }> {
    const response = await this.client.get<{ entries: LedgerEntry[]; total: number }>(
      '/api/v1/ledger',
      { params: filters },
    );
    return response.data;
  }

  async createBasket(data: {
    clientId: string;
    mandateName: string;
    chain138VaultAddress: string;
    allocations: BasketAllocation[];
    baseAssetSymbol?: string;
  }): Promise<BasketMandate> {
    const response = await this.client.post<{ basket: BasketMandate }>('/api/v1/baskets', data);
    return response.data.basket;
  }

  async createBtcDeposit(data: {
    clientId: string;
    basketId?: string;
    mandateName?: string;
    chain138VaultAddress: string;
    allocations?: BasketAllocation[];
    expectedAmountSats?: number;
    clientReference?: string;
  }): Promise<{ deposit: BtcDeposit; basket: BasketMandate; createdBasket: boolean }> {
    const response = await this.client.post<{
      deposit: BtcDeposit;
      basket: BasketMandate;
      createdBasket: boolean;
    }>('/api/v1/btc-deposits', data);
    return response.data;
  }

  async getBtcDeposit(id: string): Promise<BtcDeposit> {
    const response = await this.client.get<{ deposit: BtcDeposit }>(`/api/v1/btc-deposits/${id}`);
    return response.data.deposit;
  }

  async getHoldings(filters?: { clientId?: string; basketId?: string }): Promise<Holding[]> {
    const response = await this.client.get<{ holdings: Holding[] }>('/api/v1/holdings', {
      params: filters,
    });
    return response.data.holdings;
  }

  async getRebalances(filters?: { clientId?: string; basketId?: string }): Promise<Rebalance[]> {
    const response = await this.client.get<{ rebalances: Rebalance[] }>('/api/v1/rebalances', {
      params: filters,
    });
    return response.data.rebalances;
  }

  async requestBridgeWithdrawal(data: {
    clientId: string;
    basketId: string;
    sourceSymbol?: string;
    destinationSymbol?: string;
    destinationChainId: number;
    destinationAddress: string;
    amount: string;
  }): Promise<BridgeWithdrawal> {
    const response = await this.client.post<{ withdrawal: BridgeWithdrawal }>(
      '/api/v1/withdrawals/bridge',
      data,
    );
    return response.data.withdrawal;
  }
}
