import { useMutation, useQueryClient } from '@tanstack/react-query';
import { gql } from 'graphql-request';
import { fetchGraphQL, createQueryKey } from '../client';
import { formatDateTimeISO } from '@/lib/formatters';
import type { BankConnection } from '../queries/bankConnectionQueries';

// Types
export interface StartBankConnectionInput {
  companyId: string;
  aspspName: string;
  redirectUrl: string;
  psuType?: string;
}

export interface StartBankConnectionResult {
  connectionId: string;
  authorizationUrl: string;
}

export interface CompleteBankConnectionInput {
  connectionId: string;
  authorizationCode: string;
}

export interface LinkBankAccountInput {
  connectionId: string;
  bankAccountId: string;
  linkedAccountId: string;
  importFromDate?: string;
}

export interface ReconnectBankConnectionInput {
  connectionId: string;
  redirectUrl: string;
  psuType?: string;
}

// GraphQL Mutations
const START_BANK_CONNECTION_MUTATION = gql`
  mutation StartBankConnection($input: StartBankConnectionInput!) {
    startBankConnection(input: $input) {
      connectionId
      authorizationUrl
    }
  }
`;

const COMPLETE_BANK_CONNECTION_MUTATION = gql`
  mutation CompleteBankConnection($input: CompleteBankConnectionInput!) {
    completeBankConnection(input: $input) {
      id
      companyId
      aspspName
      status
      validUntil
      isActive
      accounts {
        accountId
        iban
        currency
        name
      }
    }
  }
`;

const DISCONNECT_BANK_CONNECTION_MUTATION = gql`
  mutation DisconnectBankConnection($id: ID!) {
    disconnectBankConnection(id: $id) {
      id
      status
      isActive
    }
  }
`;

const LINK_BANK_ACCOUNT_MUTATION = gql`
  mutation LinkBankAccount($input: LinkBankAccountInput!) {
    linkBankAccount(input: $input) {
      id
      companyId
      accounts {
        accountId
        iban
        currency
        name
        linkedAccountId
        linkedAccount {
          id
          accountNumber
          name
        }
        importFromDate
      }
    }
  }
`;

const RECONNECT_BANK_CONNECTION_MUTATION = gql`
  mutation ReconnectBankConnection($input: ReconnectBankConnectionInput!) {
    reconnectBankConnection(input: $input) {
      connectionId
      authorizationUrl
    }
  }
`;

const ARCHIVE_BANK_CONNECTION_MUTATION = gql`
  mutation ArchiveBankConnection($id: ID!) {
    archiveBankConnection(id: $id) {
      id
      status
    }
  }
`;

// Response types
interface StartBankConnectionResponse {
  startBankConnection: StartBankConnectionResult;
}

interface CompleteBankConnectionResponse {
  completeBankConnection: BankConnection;
}

interface DisconnectBankConnectionResponse {
  disconnectBankConnection: BankConnection;
}

interface LinkBankAccountResponse {
  linkBankAccount: BankConnection;
}

interface ReconnectBankConnectionResponse {
  reconnectBankConnection: StartBankConnectionResult;
}

interface ArchiveBankConnectionResponse {
  archiveBankConnection: BankConnection;
}

/**
 * Hook to start a bank connection (initiates OAuth flow)
 */
export function useStartBankConnection() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: StartBankConnectionInput) => {
      const data = await fetchGraphQL<StartBankConnectionResponse>(
        START_BANK_CONNECTION_MUTATION,
        { input }
      );
      return data.startBankConnection;
    },
    onSuccess: (_, variables) => {
      // Invalidate bank connections for the company
      queryClient.invalidateQueries({
        queryKey: createQueryKey('bankConnections', { companyId: variables.companyId }),
      });
    },
  });
}

/**
 * Hook to complete a bank connection after OAuth callback
 */
export function useCompleteBankConnection() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async (input: CompleteBankConnectionInput) => {
      const data = await fetchGraphQL<CompleteBankConnectionResponse>(
        COMPLETE_BANK_CONNECTION_MUTATION,
        { input }
      );
      return data.completeBankConnection;
    },
    onSuccess: (data) => {
      // Invalidate bank connections for the company
      queryClient.invalidateQueries({
        queryKey: createQueryKey('bankConnections', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('activeBankConnections', { companyId: data.companyId }),
      });
    },
  });
}

/**
 * Hook to disconnect a bank connection
 */
export function useDisconnectBankConnection() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ id, companyId }: { id: string; companyId: string }) => {
      const data = await fetchGraphQL<DisconnectBankConnectionResponse>(
        DISCONNECT_BANK_CONNECTION_MUTATION,
        { id }
      );
      return { ...data.disconnectBankConnection, companyId };
    },
    onSuccess: (data) => {
      // Invalidate bank connections for the company
      queryClient.invalidateQueries({
        queryKey: createQueryKey('bankConnections', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('activeBankConnections', { companyId: data.companyId }),
      });
    },
  });
}

/**
 * Hook to link a bank account to a chart of accounts account
 */
export function useLinkBankAccount() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ input, companyId }: { input: LinkBankAccountInput; companyId: string }) => {
      // Convert date to datetime for GraphQL DateTime type
      const graphqlInput = {
        ...input,
        importFromDate: input.importFromDate ? formatDateTimeISO(input.importFromDate) : undefined,
      };
      const data = await fetchGraphQL<LinkBankAccountResponse>(
        LINK_BANK_ACCOUNT_MUTATION,
        { input: graphqlInput }
      );
      return { ...data.linkBankAccount, companyId };
    },
    onSuccess: (data) => {
      // Invalidate bank connections for the company
      queryClient.invalidateQueries({
        queryKey: createQueryKey('bankConnections', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('activeBankConnections', { companyId: data.companyId }),
      });
    },
  });
}

/**
 * Hook to reconnect a disconnected/failed/expired bank connection
 */
export function useReconnectBankConnection() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ input, companyId }: { input: ReconnectBankConnectionInput; companyId: string }) => {
      const data = await fetchGraphQL<ReconnectBankConnectionResponse>(
        RECONNECT_BANK_CONNECTION_MUTATION,
        { input }
      );
      return { ...data.reconnectBankConnection, companyId };
    },
    onSuccess: (_, variables) => {
      // Invalidate bank connections for the company
      queryClient.invalidateQueries({
        queryKey: createQueryKey('bankConnections', { companyId: variables.companyId }),
      });
    },
  });
}

/**
 * Hook to archive a bank connection (hide from UI)
 */
export function useArchiveBankConnection() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: async ({ id, companyId }: { id: string; companyId: string }) => {
      const data = await fetchGraphQL<ArchiveBankConnectionResponse>(
        ARCHIVE_BANK_CONNECTION_MUTATION,
        { id }
      );
      return { ...data.archiveBankConnection, companyId };
    },
    onSuccess: (data) => {
      // Invalidate bank connections for the company
      queryClient.invalidateQueries({
        queryKey: createQueryKey('bankConnections', { companyId: data.companyId }),
      });
      queryClient.invalidateQueries({
        queryKey: createQueryKey('activeBankConnections', { companyId: data.companyId }),
      });
    },
  });
}
