import { useQuery, useMutation, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
import { gql } from 'graphql-request';
import { fetchGraphQL, createQueryKey } from '../client';

// GraphQL Queries
const PENDING_BANK_TRANSACTIONS_QUERY = gql`
  query PendingBankTransactions($companyId: ID!) {
    pendingBankTransactions(companyId: $companyId) {
      id
      companyId
      bankConnectionId
      bankAccountId
      externalId
      amount
      currency
      transactionDate
      bookingDate
      valueDate
      description
      counterpartyName
      counterpartyAccount
      reference
      creditorName
      debtorName
      status
      journalEntryDraftId
      createdAt
      updatedAt
      displayCounterparty
      isIncome
    }
  }
`;

const BANK_TRANSACTIONS_QUERY = gql`
  query BankTransactions($companyId: ID!) {
    bankTransactions(companyId: $companyId) {
      id
      companyId
      bankAccountId
      amount
      currency
      transactionDate
      description
      counterpartyName
      status
      journalEntryDraftId
      displayCounterparty
      isIncome
    }
  }
`;

const SYNC_BANK_TRANSACTIONS_MUTATION = gql`
  mutation SyncBankTransactions($companyId: ID!) {
    syncBankTransactions(companyId: $companyId) {
      totalConnections
      totalAccounts
      newTransactions
      skippedDuplicates
      errors
      errorMessages
    }
  }
`;

const MARK_BANK_TRANSACTION_BOOKED_MUTATION = gql`
  mutation MarkBankTransactionBooked($id: ID!, $journalEntryDraftId: ID!) {
    markBankTransactionBooked(id: $id, journalEntryDraftId: $journalEntryDraftId) {
      id
      status
      journalEntryDraftId
    }
  }
`;

const IGNORE_BANK_TRANSACTION_MUTATION = gql`
  mutation IgnoreBankTransaction($id: ID!) {
    ignoreBankTransaction(id: $id) {
      id
      status
    }
  }
`;

// Response types
export interface BankTransactionResponse {
  id: string;
  companyId: string;
  bankConnectionId: string;
  bankAccountId: string;
  externalId: string;
  amount: number;
  currency: string;
  transactionDate: string;
  bookingDate?: string;
  valueDate?: string;
  description?: string;
  counterpartyName?: string;
  counterpartyAccount?: string;
  reference?: string;
  creditorName?: string;
  debtorName?: string;
  status: 'pending' | 'booked' | 'ignored';
  journalEntryDraftId?: string;
  createdAt: string;
  updatedAt: string;
  displayCounterparty: string;
  isIncome: boolean;
}

interface PendingBankTransactionsResponse {
  pendingBankTransactions: BankTransactionResponse[];
}

interface BankTransactionsResponse {
  bankTransactions: BankTransactionResponse[];
}

export interface SyncResult {
  totalConnections: number;
  totalAccounts: number;
  newTransactions: number;
  skippedDuplicates: number;
  errors: number;
  errorMessages: string[];
}

interface SyncBankTransactionsResponse {
  syncBankTransactions: SyncResult;
}

// Transform to store format (compatible with PendingBankTransaction in store)
// Named QuickBookingTransaction to distinguish from BankTransaction in types/accounting.ts (used for reconciliation)
export interface QuickBookingTransaction {
  id: string;
  date: string;
  amount: number;
  description: string;
  counterparty: string;
  bankAccountId: string;
  bankAccountNumber: string;
  isBooked: boolean;
  bookedAt?: string;
  transactionId?: string;
}

function transformToQuickBookingTransaction(tx: BankTransactionResponse): QuickBookingTransaction {
  return {
    id: tx.id,
    date: tx.transactionDate,
    amount: tx.amount,
    description: tx.description || '',
    counterparty: tx.displayCounterparty,
    bankAccountId: tx.bankAccountId,
    bankAccountNumber: tx.counterpartyAccount || tx.bankAccountId,
    isBooked: tx.status === 'booked',
    bookedAt: tx.status === 'booked' ? tx.updatedAt : undefined,
    transactionId: tx.journalEntryDraftId,
  };
}

// Query hooks
export function usePendingBankTransactions(
  companyId: string | undefined,
  options?: Omit<UseQueryOptions<QuickBookingTransaction[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('pendingBankTransactions', { companyId }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<PendingBankTransactionsResponse>(
        PENDING_BANK_TRANSACTIONS_QUERY,
        { companyId }
      );
      return data.pendingBankTransactions.map(transformToQuickBookingTransaction);
    },
    enabled: !!companyId,
    ...options,
  });
}

export function useBankTransactions(
  companyId: string | undefined,
  options?: Omit<UseQueryOptions<QuickBookingTransaction[], Error>, 'queryKey' | 'queryFn'>
) {
  return useQuery({
    queryKey: createQueryKey('bankTransactions', { companyId }),
    queryFn: async () => {
      if (!companyId) return [];
      const data = await fetchGraphQL<BankTransactionsResponse>(
        BANK_TRANSACTIONS_QUERY,
        { companyId }
      );
      return data.bankTransactions.map(transformToQuickBookingTransaction);
    },
    enabled: !!companyId,
    ...options,
  });
}

// Mutation hooks
export function useSyncBankTransactions() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (companyId: string) => {
      const data = await fetchGraphQL<SyncBankTransactionsResponse>(
        SYNC_BANK_TRANSACTIONS_MUTATION,
        { companyId }
      );
      return data.syncBankTransactions;
    },
    onSuccess: (_, companyId) => {
      // Invalidate pending transactions query to refresh the list
      queryClient.invalidateQueries({
        queryKey: createQueryKey('pendingBankTransactions', { companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('bankTransactions', { companyId }),
      });
    },
  });
}

export function useMarkBankTransactionBooked() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({
      id,
      journalEntryDraftId,
    }: {
      id: string;
      journalEntryDraftId: string;
    }) => {
      const data = await fetchGraphQL<{ markBankTransactionBooked: BankTransactionResponse }>(
        MARK_BANK_TRANSACTION_BOOKED_MUTATION,
        { id, journalEntryDraftId }
      );
      return data.markBankTransactionBooked;
    },
    onSuccess: () => {
      // Invalidate all bank transaction queries
      queryClient.invalidateQueries({
        predicate: (query) =>
          query.queryKey[0] === 'pendingBankTransactions' ||
          query.queryKey[0] === 'bankTransactions',
      });
    },
  });
}

export function useIgnoreBankTransaction() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (id: string) => {
      const data = await fetchGraphQL<{ ignoreBankTransaction: BankTransactionResponse }>(
        IGNORE_BANK_TRANSACTION_MUTATION,
        { id }
      );
      return data.ignoreBankTransaction;
    },
    onSuccess: () => {
      // Invalidate all bank transaction queries
      queryClient.invalidateQueries({
        predicate: (query) =>
          query.queryKey[0] === 'pendingBankTransactions' ||
          query.queryKey[0] === 'bankTransactions',
      });
    },
  });
}
