/**
 * Xero Bank Transaction Tools
 * Handles bank transactions - money in (RECEIVE) and money out (SPEND)
 */

import { z } from 'zod';
import { XeroClient } from '../clients/xero.js';
import type { Tool } from '@modelcontextprotocol/sdk/types.js';

const LineItemSchema = z.object({
  Description: z.string().optional(),
  Quantity: z.number().optional(),
  UnitAmount: z.number().optional(),
  AccountCode: z.string().optional(),
  TaxType: z.string().optional(),
  LineAmount: z.number().optional()
});

const ContactSchema = z.object({
  ContactID: z.string().optional(),
  Name: z.string().optional()
});

const BankAccountSchema = z.object({
  AccountID: z.string().optional(),
  Code: z.string().optional()
});

export function getTools(_client: XeroClient): Tool[] {
  return [
    // List bank transactions
    {
      name: 'xero_list_bank_transactions',
      description: 'List all bank transactions. Use where clause to filter by Type (RECEIVE/SPEND), Status, or BankAccount.',
      inputSchema: {
        type: 'object',
        properties: {
          page: { type: 'number', description: 'Page number (default 1)' },
          pageSize: { type: 'number', description: 'Page size (max 100)' },
          where: { type: 'string', description: 'Filter expression (e.g., Type=="RECEIVE")' },
          order: { type: 'string', description: 'Order by field (e.g., Date DESC)' },
          ifModifiedSince: { type: 'string', description: 'ISO date to get only records modified since' }
        }
      }
    },

    // Get single bank transaction
    {
      name: 'xero_get_bank_transaction',
      description: 'Get a specific bank transaction by ID. Returns full details including line items.',
      inputSchema: {
        type: 'object',
        properties: {
          bankTransactionId: { type: 'string', description: 'Bank transaction ID (GUID)' }
        },
        required: ['bankTransactionId']
      }
    },

    // Create bank transaction
    {
      name: 'xero_create_bank_transaction',
      description: 'Create a new bank transaction. Type must be RECEIVE (money in) or SPEND (money out).',
      inputSchema: {
        type: 'object',
        properties: {
          type: {
            type: 'string',
            enum: ['RECEIVE', 'SPEND'],
            description: 'Transaction type: RECEIVE (money in) or SPEND (money out)'
          },
          contact: {
            type: 'object',
            properties: {
              ContactID: { type: 'string', description: 'Contact ID (GUID)' },
              Name: { type: 'string', description: 'Contact name' }
            },
            description: 'Contact associated with transaction'
          },
          bankAccount: {
            type: 'object',
            properties: {
              AccountID: { type: 'string', description: 'Bank account ID (GUID)' },
              Code: { type: 'string', description: 'Bank account code' }
            },
            description: 'Bank account (must be a BANK type account)'
          },
          lineItems: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                Description: { type: 'string' },
                Quantity: { type: 'number' },
                UnitAmount: { type: 'number' },
                AccountCode: { type: 'string' },
                TaxType: { type: 'string' },
                LineAmount: { type: 'number' }
              }
            },
            description: 'Line items (at least one required)'
          },
          date: { type: 'string', description: 'Transaction date (YYYY-MM-DD)' },
          reference: { type: 'string', description: 'Reference text' },
          isReconciled: { type: 'boolean', description: 'Mark as reconciled' },
          status: {
            type: 'string',
            enum: ['AUTHORISED'],
            description: 'Status (must be AUTHORISED for bank transactions)'
          }
        },
        required: ['type', 'contact', 'bankAccount', 'lineItems']
      }
    },

    // Update bank transaction
    {
      name: 'xero_update_bank_transaction',
      description: 'Update an existing bank transaction. Can update reference, line items, and reconciliation status.',
      inputSchema: {
        type: 'object',
        properties: {
          bankTransactionId: { type: 'string', description: 'Bank transaction ID (GUID)' },
          reference: { type: 'string', description: 'Reference text' },
          isReconciled: { type: 'boolean', description: 'Mark as reconciled/unreconciled' },
          lineItems: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                Description: { type: 'string' },
                Quantity: { type: 'number' },
                UnitAmount: { type: 'number' },
                AccountCode: { type: 'string' }
              }
            }
          }
        },
        required: ['bankTransactionId']
      }
    },

    // Void bank transaction
    {
      name: 'xero_void_bank_transaction',
      description: 'Void a bank transaction. This sets the status to VOIDED.',
      inputSchema: {
        type: 'object',
        properties: {
          bankTransactionId: { type: 'string', description: 'Bank transaction ID (GUID)' }
        },
        required: ['bankTransactionId']
      }
    }
  ];
}

export async function handleBankTransactionTool(
  toolName: string,
  args: Record<string, unknown>,
  client: XeroClient
): Promise<unknown> {
  switch (toolName) {
    case 'xero_list_bank_transactions': {
      const options = {
        page: args.page as number | undefined,
        pageSize: args.pageSize as number | undefined,
        where: args.where as string | undefined,
        order: args.order as string | undefined,
        ifModifiedSince: args.ifModifiedSince ? new Date(args.ifModifiedSince as string) : undefined
      };
      return await client.getBankTransactions(options);
    }

    case 'xero_get_bank_transaction': {
      const { bankTransactionId } = z.object({ bankTransactionId: z.string() }).parse(args);
      return await client.getBankTransaction(bankTransactionId as any);
    }

    case 'xero_create_bank_transaction': {
      const schema = z.object({
        type: z.enum(['RECEIVE', 'SPEND']),
        contact: ContactSchema,
        bankAccount: BankAccountSchema,
        lineItems: z.array(LineItemSchema).min(1),
        date: z.string().optional(),
        reference: z.string().optional(),
        isReconciled: z.boolean().optional(),
        status: z.enum(['AUTHORISED']).default('AUTHORISED')
      });
      const data = schema.parse(args);
      
      const transaction: any = {
        Type: data.type,
        Contact: data.contact,
        BankAccount: data.bankAccount,
        LineItems: data.lineItems,
        Status: data.status
      };
      
      if (data.date) transaction.Date = data.date;
      if (data.reference) transaction.Reference = data.reference;
      if (data.isReconciled !== undefined) transaction.IsReconciled = data.isReconciled;
      
      return await client.createBankTransaction(transaction);
    }

    case 'xero_update_bank_transaction': {
      const schema = z.object({
        bankTransactionId: z.string(),
        reference: z.string().optional(),
        isReconciled: z.boolean().optional(),
        lineItems: z.array(LineItemSchema).optional()
      });
      const data = schema.parse(args);
      
      const updates: any = {};
      if (data.reference) updates.Reference = data.reference;
      if (data.isReconciled !== undefined) updates.IsReconciled = data.isReconciled;
      if (data.lineItems) updates.LineItems = data.lineItems;
      
      return await client.updateBankTransaction(data.bankTransactionId as any, updates);
    }

    case 'xero_void_bank_transaction': {
      const { bankTransactionId } = z.object({ bankTransactionId: z.string() }).parse(args);
      return await client.updateBankTransaction(bankTransactionId as any, { Status: 'VOIDED' as any });
    }

    default:
      throw new Error(`Unknown bank transaction tool: ${toolName}`);
  }
}
