import { QuickBooksClient } from '../clients/quickbooks.js';
import type { JournalEntry, Deposit, Transfer } from '../types/index.js';

export function getTools(client: QuickBooksClient) {
  return [
    {
      name: 'qbo_list_journal_entries',
      description: 'List journal entries with optional filters',
      inputSchema: {
        type: 'object',
        properties: {
          startPosition: {
            type: 'number',
            description: 'Starting position (1-indexed, default 1)',
          },
          maxResults: {
            type: 'number',
            description: 'Maximum results to return (max 1000, default 100)',
          },
        },
      },
      handler: async (args: any) => {
        const { startPosition = 1, maxResults = 100 } = args;
        const query = 'SELECT * FROM JournalEntry';
        
        return await client.query<JournalEntry>(query, { startPosition, maxResults });
      },
    },
    {
      name: 'qbo_get_journal_entry',
      description: 'Get a specific journal entry by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Journal entry ID',
          },
        },
        required: ['id'],
      },
      handler: async (args: any) => {
        return await client.read<JournalEntry>('JournalEntry', args.id);
      },
    },
    {
      name: 'qbo_create_journal_entry',
      description: 'Create a new journal entry (debits and credits must balance)',
      inputSchema: {
        type: 'object',
        properties: {
          lines: {
            type: 'array',
            description: 'Journal entry lines (must have both debits and credits that balance)',
            items: {
              type: 'object',
              properties: {
                accountId: { type: 'string' },
                amount: { type: 'number' },
                detailType: { 
                  type: 'string',
                  description: 'JournalEntryLineDetail',
                },
                postingType: { 
                  type: 'string',
                  description: 'Debit or Credit',
                },
                description: { type: 'string' },
              },
            },
          },
          txnDate: {
            type: 'string',
            description: 'Transaction date (YYYY-MM-DD)',
          },
          privateNote: {
            type: 'string',
            description: 'Private note',
          },
        },
        required: ['lines'],
      },
      handler: async (args: any) => {
        const journalEntry: any = {
          Line: args.lines.map((line: any) => ({
            Amount: line.amount,
            DetailType: 'JournalEntryLineDetail',
            Description: line.description,
            JournalEntryLineDetail: {
              AccountRef: { value: line.accountId },
              PostingType: line.postingType,
            },
          })),
        };
        
        if (args.txnDate) journalEntry.TxnDate = args.txnDate;
        if (args.privateNote) journalEntry.PrivateNote = args.privateNote;
        
        return await client.create<JournalEntry>('JournalEntry', journalEntry);
      },
    },
    {
      name: 'qbo_update_journal_entry',
      description: 'Update an existing journal entry (requires SyncToken)',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Journal entry ID',
          },
          syncToken: {
            type: 'string',
            description: 'SyncToken from the journal entry',
          },
          lines: {
            type: 'array',
            description: 'Updated journal entry lines',
          },
        },
        required: ['id', 'syncToken'],
      },
      handler: async (args: any) => {
        const journalEntry: any = {
          Id: args.id,
          SyncToken: args.syncToken,
        };
        
        if (args.lines) journalEntry.Line = args.lines;
        
        return await client.update<JournalEntry>('JournalEntry', journalEntry);
      },
    },
    {
      name: 'qbo_delete_journal_entry',
      description: 'Delete a journal entry (requires SyncToken)',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Journal entry ID',
          },
          syncToken: {
            type: 'string',
            description: 'SyncToken from the journal entry',
          },
        },
        required: ['id', 'syncToken'],
      },
      handler: async (args: any) => {
        return await client.delete('JournalEntry', args.id, args.syncToken);
      },
    },
    {
      name: 'qbo_list_deposits',
      description: 'List deposits with optional filters',
      inputSchema: {
        type: 'object',
        properties: {
          startPosition: {
            type: 'number',
            description: 'Starting position (1-indexed, default 1)',
          },
          maxResults: {
            type: 'number',
            description: 'Maximum results to return (max 1000, default 100)',
          },
          accountId: {
            type: 'string',
            description: 'Filter by deposit account ID',
          },
        },
      },
      handler: async (args: any) => {
        const { startPosition = 1, maxResults = 100, accountId } = args;
        
        let query = 'SELECT * FROM Deposit';
        if (accountId) {
          query += ` WHERE DepositToAccountRef = '${accountId}'`;
        }
        
        return await client.query<Deposit>(query, { startPosition, maxResults });
      },
    },
    {
      name: 'qbo_get_deposit',
      description: 'Get a specific deposit by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Deposit ID',
          },
        },
        required: ['id'],
      },
      handler: async (args: any) => {
        return await client.read<Deposit>('Deposit', args.id);
      },
    },
    {
      name: 'qbo_create_deposit',
      description: 'Create a new deposit',
      inputSchema: {
        type: 'object',
        properties: {
          depositToAccountId: {
            type: 'string',
            description: 'Deposit to account ID (bank account)',
          },
          lines: {
            type: 'array',
            description: 'Deposit line items',
            items: {
              type: 'object',
              properties: {
                amount: { type: 'number' },
                description: { type: 'string' },
                accountId: { type: 'string' },
                linkedTxnId: { type: 'string' },
              },
            },
          },
          txnDate: {
            type: 'string',
            description: 'Transaction date (YYYY-MM-DD)',
          },
        },
        required: ['depositToAccountId', 'lines'],
      },
      handler: async (args: any) => {
        const deposit: any = {
          DepositToAccountRef: { value: args.depositToAccountId },
          Line: args.lines.map((line: any) => ({
            Amount: line.amount,
            DetailType: 'DepositLineDetail',
            Description: line.description,
            DepositLineDetail: {
              AccountRef: { value: line.accountId },
              ...(line.linkedTxnId && {
                Entity: { value: line.linkedTxnId },
              }),
            },
          })),
        };
        
        if (args.txnDate) deposit.TxnDate = args.txnDate;
        
        return await client.create<Deposit>('Deposit', deposit);
      },
    },
    {
      name: 'qbo_delete_deposit',
      description: 'Delete a deposit (requires SyncToken)',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Deposit ID',
          },
          syncToken: {
            type: 'string',
            description: 'SyncToken from the deposit',
          },
        },
        required: ['id', 'syncToken'],
      },
      handler: async (args: any) => {
        return await client.delete('Deposit', args.id, args.syncToken);
      },
    },
    {
      name: 'qbo_list_transfers',
      description: 'List transfers with optional filters',
      inputSchema: {
        type: 'object',
        properties: {
          startPosition: {
            type: 'number',
            description: 'Starting position (1-indexed, default 1)',
          },
          maxResults: {
            type: 'number',
            description: 'Maximum results to return (max 1000, default 100)',
          },
        },
      },
      handler: async (args: any) => {
        const { startPosition = 1, maxResults = 100 } = args;
        const query = 'SELECT * FROM Transfer';
        
        return await client.query<Transfer>(query, { startPosition, maxResults });
      },
    },
    {
      name: 'qbo_get_transfer',
      description: 'Get a specific transfer by ID',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Transfer ID',
          },
        },
        required: ['id'],
      },
      handler: async (args: any) => {
        return await client.read<Transfer>('Transfer', args.id);
      },
    },
    {
      name: 'qbo_create_transfer',
      description: 'Create a new transfer between accounts',
      inputSchema: {
        type: 'object',
        properties: {
          fromAccountId: {
            type: 'string',
            description: 'From account ID',
          },
          toAccountId: {
            type: 'string',
            description: 'To account ID',
          },
          amount: {
            type: 'number',
            description: 'Transfer amount',
          },
          txnDate: {
            type: 'string',
            description: 'Transaction date (YYYY-MM-DD)',
          },
        },
        required: ['fromAccountId', 'toAccountId', 'amount'],
      },
      handler: async (args: any) => {
        const transfer: any = {
          FromAccountRef: { value: args.fromAccountId },
          ToAccountRef: { value: args.toAccountId },
          Amount: args.amount,
        };
        
        if (args.txnDate) transfer.TxnDate = args.txnDate;
        
        return await client.create<Transfer>('Transfer', transfer);
      },
    },
    {
      name: 'qbo_delete_transfer',
      description: 'Delete a transfer (requires SyncToken)',
      inputSchema: {
        type: 'object',
        properties: {
          id: {
            type: 'string',
            description: 'Transfer ID',
          },
          syncToken: {
            type: 'string',
            description: 'SyncToken from the transfer',
          },
        },
        required: ['id', 'syncToken'],
      },
      handler: async (args: any) => {
        return await client.delete('Transfer', args.id, args.syncToken);
      },
    },
  ];
}
