import { z } from 'zod';
import type { AirtableClient } from '../clients/airtable.js';
import { BaseIdSchema, RecordIdSchema, SortConfigSchema } from '../types/index.js';

/**
 * Records Tools
 * 
 * Tools for managing records (rows) in Airtable tables.
 * Batch operations limited to 10 records per request.
 */

export function getTools(client: AirtableClient) {
  return [
    // ========================================================================
    // List Records
    // ========================================================================
    {
      name: 'airtable_list_records',
      description:
        'List records from a table with optional filtering, sorting, and pagination. Use filterByFormula for complex queries (Airtable formula syntax). Returns up to 100 records per page (use offset for more).',
      inputSchema: z.object({
        baseId: BaseIdSchema.describe('The ID of the base (starts with app).'),
        tableIdOrName: z
          .string()
          .describe('Table ID (starts with tbl) or table name (URL-encoded if needed).'),
        fields: z
          .array(z.string())
          .optional()
          .describe('Array of field names to include. Omit to return all fields.'),
        filterByFormula: z
          .string()
          .optional()
          .describe(
            'Airtable formula to filter records (e.g., "{Status} = \'Done\'", "AND({Priority} = \'High\', {Done} = 0)").'
          ),
        maxRecords: z
          .number()
          .optional()
          .describe('Maximum number of records to return (across all pages).'),
        pageSize: z
          .number()
          .max(100)
          .optional()
          .describe('Number of records per page (max 100).'),
        sort: z
          .array(SortConfigSchema)
          .optional()
          .describe('Array of sort configurations with field name and direction (asc/desc).'),
        view: z
          .string()
          .optional()
          .describe('Name or ID of a view to use. Applies that view\'s filters and sorting.'),
        offset: z
          .string()
          .optional()
          .describe('Pagination offset from previous response.'),
        cellFormat: z
          .enum(['json', 'string'])
          .optional()
          .describe('Format for cell values (json for structured data, string for display).'),
        timeZone: z
          .string()
          .optional()
          .describe('IANA timezone for date/time fields (e.g., America/New_York).'),
        userLocale: z
          .string()
          .optional()
          .describe('Locale for formatting (e.g., en-US).'),
        returnFieldsByFieldId: z
          .boolean()
          .optional()
          .describe('Return fields keyed by field ID instead of field name.'),
      }),
      execute: async (args: {
        baseId: string;
        tableIdOrName: string;
        fields?: string[];
        filterByFormula?: string;
        maxRecords?: number;
        pageSize?: number;
        sort?: Array<{ field: string; direction: 'asc' | 'desc' }>;
        view?: string;
        offset?: string;
        cellFormat?: 'json' | 'string';
        timeZone?: string;
        userLocale?: string;
        returnFieldsByFieldId?: boolean;
      }) => {
        const response = await client.listRecords(args.baseId as any, args.tableIdOrName, {
          fields: args.fields,
          filterByFormula: args.filterByFormula,
          maxRecords: args.maxRecords,
          pageSize: args.pageSize,
          sort: args.sort,
          view: args.view,
          offset: args.offset,
          cellFormat: args.cellFormat,
          timeZone: args.timeZone,
          userLocale: args.userLocale,
          returnFieldsByFieldId: args.returnFieldsByFieldId,
        });
        return {
          records: response.records,
          offset: response.offset,
          hasMore: !!response.offset,
        };
      },
    },

    // ========================================================================
    // Get Record
    // ========================================================================
    {
      name: 'airtable_get_record',
      description:
        'Get a single record by ID. Returns all fields and metadata.',
      inputSchema: z.object({
        baseId: BaseIdSchema.describe('The ID of the base (starts with app).'),
        tableIdOrName: z
          .string()
          .describe('Table ID (starts with tbl) or table name.'),
        recordId: RecordIdSchema.describe('The ID of the record (starts with rec).'),
      }),
      execute: async (args: {
        baseId: string;
        tableIdOrName: string;
        recordId: string;
      }) => {
        const record = await client.getRecord(
          args.baseId as any,
          args.tableIdOrName,
          args.recordId as any
        );
        return record;
      },
    },

    // ========================================================================
    // Create Records (Batch)
    // ========================================================================
    {
      name: 'airtable_create_records',
      description:
        'Create up to 10 records in a single request. Each record must specify its fields as key-value pairs. Use typecast to automatically convert strings to appropriate types.',
      inputSchema: z.object({
        baseId: BaseIdSchema.describe('The ID of the base (starts with app).'),
        tableIdOrName: z
          .string()
          .describe('Table ID (starts with tbl) or table name.'),
        records: z
          .array(
            z.object({
              fields: z
                .record(z.unknown())
                .describe('Field values as key-value pairs (field name: value).'),
            })
          )
          .max(10)
          .min(1)
          .describe('Array of records to create (max 10).'),
        typecast: z
          .boolean()
          .optional()
          .describe('Automatically convert string values to field types (e.g., "42" to number).'),
      }),
      execute: async (args: {
        baseId: string;
        tableIdOrName: string;
        records: Array<{ fields: Record<string, unknown> }>;
        typecast?: boolean;
      }) => {
        const response = await client.createRecords(
          args.baseId as any,
          args.tableIdOrName,
          args.records,
          args.typecast
        );
        return {
          records: response.records,
          createdCount: response.records.length,
        };
      },
    },

    // ========================================================================
    // Update Records (Batch)
    // ========================================================================
    {
      name: 'airtable_update_records',
      description:
        'Update up to 10 records in a single request. Each record must include its ID and the fields to update. Unspecified fields are not modified.',
      inputSchema: z.object({
        baseId: BaseIdSchema.describe('The ID of the base (starts with app).'),
        tableIdOrName: z
          .string()
          .describe('Table ID (starts with tbl) or table name.'),
        records: z
          .array(
            z.object({
              id: RecordIdSchema.describe('The ID of the record to update (starts with rec).'),
              fields: z
                .record(z.unknown())
                .describe('Field values to update (field name: new value).'),
            })
          )
          .max(10)
          .min(1)
          .describe('Array of records to update (max 10).'),
        typecast: z
          .boolean()
          .optional()
          .describe('Automatically convert string values to field types.'),
      }),
      execute: async (args: {
        baseId: string;
        tableIdOrName: string;
        records: Array<{ id: string; fields: Record<string, unknown> }>;
        typecast?: boolean;
      }) => {
        const response = await client.updateRecords(
          args.baseId as any,
          args.tableIdOrName,
          args.records as any,
          args.typecast
        );
        return {
          records: response.records,
          updatedCount: response.records.length,
        };
      },
    },

    // ========================================================================
    // Delete Records (Batch)
    // ========================================================================
    {
      name: 'airtable_delete_records',
      description:
        'Delete up to 10 records in a single request. Provide an array of record IDs to delete.',
      inputSchema: z.object({
        baseId: BaseIdSchema.describe('The ID of the base (starts with app).'),
        tableIdOrName: z
          .string()
          .describe('Table ID (starts with tbl) or table name.'),
        recordIds: z
          .array(RecordIdSchema)
          .max(10)
          .min(1)
          .describe('Array of record IDs to delete (max 10, starts with rec).'),
      }),
      execute: async (args: {
        baseId: string;
        tableIdOrName: string;
        recordIds: string[];
      }) => {
        const response = await client.deleteRecords(
          args.baseId as any,
          args.tableIdOrName,
          args.recordIds as any
        );
        return {
          records: response.records,
          deletedCount: response.records.filter((r) => r.deleted).length,
        };
      },
    },

    // ========================================================================
    // Search Records
    // ========================================================================
    {
      name: 'airtable_search_records',
      description:
        'Search records using filterByFormula with common search patterns. This is a convenience wrapper around list_records optimized for search use cases.',
      inputSchema: z.object({
        baseId: BaseIdSchema.describe('The ID of the base (starts with app).'),
        tableIdOrName: z
          .string()
          .describe('Table ID (starts with tbl) or table name.'),
        searchField: z
          .string()
          .describe('The field name to search in.'),
        searchValue: z
          .string()
          .describe('The value to search for.'),
        matchType: z
          .enum(['exact', 'contains', 'starts_with'])
          .optional()
          .describe('Type of match: exact, contains, or starts_with. Default: contains.'),
        maxRecords: z
          .number()
          .optional()
          .describe('Maximum number of results to return.'),
        fields: z
          .array(z.string())
          .optional()
          .describe('Fields to include in results.'),
      }),
      execute: async (args: {
        baseId: string;
        tableIdOrName: string;
        searchField: string;
        searchValue: string;
        matchType?: 'exact' | 'contains' | 'starts_with';
        maxRecords?: number;
        fields?: string[];
      }) => {
        const matchType = args.matchType || 'contains';
        let formula: string;

        // Escape single quotes in search value
        const escapedValue = args.searchValue.replace(/'/g, "\\'");

        switch (matchType) {
          case 'exact':
            formula = `{${args.searchField}} = '${escapedValue}'`;
            break;
          case 'starts_with':
            formula = `FIND('${escapedValue}', {${args.searchField}}) = 1`;
            break;
          case 'contains':
          default:
            formula = `FIND('${escapedValue}', {${args.searchField}}) > 0`;
            break;
        }

        const response = await client.listRecords(args.baseId as any, args.tableIdOrName, {
          filterByFormula: formula,
          maxRecords: args.maxRecords,
          fields: args.fields,
        });

        return {
          records: response.records,
          count: response.records.length,
          searchField: args.searchField,
          searchValue: args.searchValue,
          matchType,
        };
      },
    },
  ];
}
