import type { z } from 'zod'
import type { Tool, ToolExecutionOptions } from '../types'
import { ToolingError } from '../types'
import { getToolServices } from '../registry'

/**
 * Supported integration types
 *
 * These represent the available integration adapters that can be used with tools.
 * Each integration type corresponds to an adapter implementation.
 *
 * Note: Concrete adapter implementations are deferred until needed.
 * This type provides compile-time safety and auto-completion for tool definitions.
 */
export type IntegrationType =
  | 'gmail' // Google Gmail API
  | 'google-sheets' // Google Sheets API
  | 'slack' // Slack API
  | 'github' // GitHub API
  | 'linear' // Linear API
  | 'attio' // Attio CRM API
  | 'airtable' // Airtable API
  | 'salesforce' // Salesforce API
  | 'hubspot' // HubSpot API
  | 'stripe' // Stripe API
  | 'twilio' // Twilio API
  | 'sendgrid' // SendGrid API
  | 'mailgun' // Mailgun API
  | 'zapier' // Zapier Webhooks
  | 'webhook' // Generic webhook
  | 'apify' // Apify actor automation
  | 'instantly' // Instantly.ai email automation
  | 'resend' // Resend transactional email API
  | 'signature-api' // SignatureAPI eSignature service
  | 'dropbox' // Dropbox file storage API
  | 'anymailfinder' // Anymailfinder email finder API
  | 'tomba' // Tomba email discovery API
  | 'millionverifier' // MillionVerifier email verification API

/**
 * Type-safe method names for each integration
 * Provides compile-time validation and IDE auto-completion
 */
export type GmailMethod = 'sendEmail' | 'searchEmails' | 'readEmail' | 'createDraft' | 'addLabel'
export type SlackMethod = 'postMessage' | 'listChannels' | 'createChannel' | 'uploadFile' | 'addReaction'
export type GithubMethod = 'createIssue' | 'createPR' | 'addComment' | 'listIssues'
export type LinearMethod = 'createIssue' | 'updateIssue' | 'listIssues'
export type AttioMethod =
  | 'createRecord'
  | 'updateRecord'
  | 'listRecords'
  | 'getRecord'
  | 'deleteRecord'
  | 'createTask'
  | 'createNote'
  | 'listNotes'
  | 'deleteNote'
  | 'listObjects'
  | 'listAttributes'
  | 'createAttribute'
  | 'updateAttribute'
export type AirtableMethod = 'listRecords' | 'createRecord' | 'updateRecord' | 'deleteRecord'
export type SalesforceMethod = 'query' | 'create' | 'update' | 'delete'
export type HubspotMethod = 'createContact' | 'updateContact' | 'listContacts'
export type StripeMethod =
  | 'createPaymentLink'
  | 'getPaymentLink'
  | 'updatePaymentLink'
  | 'listPaymentLinks'
  | 'createCheckoutSession'
  | 'createAutoPaymentLink'
export type TwilioMethod = 'sendSMS' | 'sendWhatsApp' | 'makeCall'
export type SendgridMethod = 'sendEmail' | 'addToList'
export type MailgunMethod = 'sendEmail' | 'validateEmail'
export type ZapierMethod = 'trigger'
export type WebhookMethod = 'call'
export type GoogleSheetsMethod =
  | 'readSheet'
  | 'writeSheet'
  | 'appendRows'
  | 'clearRange'
  | 'getSpreadsheetMetadata'
  | 'batchUpdate'
  | 'getHeaders'
  | 'getLastRow'
  | 'getRowByValue'
  | 'updateRowByValue'
  | 'upsertRow'
  | 'filterRows'
  | 'deleteRowByValue'
export type ApifyMethod = 'runActor' | 'getDatasetItems' | 'startActor'
export type InstantlyMethod =
  | 'sendReply'
  | 'updateInterestStatus'
  | 'removeFromSubsequence'
  | 'deleteLead'
  | 'moveLead'
  | 'getEmails'
  | 'addToCampaign'
  | 'listCampaigns'
  | 'getCampaign'
  | 'updateCampaign'
  | 'pauseCampaign'
  | 'activateCampaign'
  | 'getCampaignAnalytics'
  | 'getStepAnalytics'
  | 'bulkAddLeads'
  | 'getAccountHealth'
  | 'createInboxTest'
  | 'createCampaign'
  | 'getDailyCampaignAnalytics'
  | 'listLeads'
  | 'bulkDeleteLeads'
  | 'deleteCampaign'
export type ResendMethod = 'sendEmail' | 'getEmail'
export type SignatureApiMethod = 'createEnvelope' | 'voidEnvelope' | 'downloadDocument' | 'getEnvelope'
export type DropboxMethod = 'uploadFile' | 'createFolder'
export type AnymailfinderMethod = 'findCompanyEmail' | 'findPersonEmail' | 'findDecisionMakerEmail' | 'verifyEmail'
export type TombaMethod = 'emailFinder' | 'domainSearch' | 'emailVerifier'
export type MillionVerifierMethod = 'verifyEmail' | 'checkCredits'

/**
 * Map integration types to their method types
 */
export type IntegrationMethodMap = {
  gmail: GmailMethod
  'google-sheets': GoogleSheetsMethod
  slack: SlackMethod
  github: GithubMethod
  linear: LinearMethod
  attio: AttioMethod
  airtable: AirtableMethod
  salesforce: SalesforceMethod
  hubspot: HubspotMethod
  stripe: StripeMethod
  twilio: TwilioMethod
  sendgrid: SendgridMethod
  mailgun: MailgunMethod
  zapier: ZapierMethod
  webhook: WebhookMethod
  apify: ApifyMethod
  instantly: InstantlyMethod
  resend: ResendMethod
  'signature-api': SignatureApiMethod
  dropbox: DropboxMethod
  anymailfinder: AnymailfinderMethod
  tomba: TombaMethod
  millionverifier: MillionVerifierMethod
}

/**
 * Configuration for creating an integration tool.
 * Integration tools call external APIs (Gmail, Slack, etc.) using organization credentials.
 *
 * @template T - Integration type (e.g., 'gmail', 'slack')
 */
export interface IntegrationToolConfig<T extends IntegrationType = IntegrationType> {
  /** Unique name for the tool (e.g., 'gmail_sendEmail', 'slack_postMessage') */
  name: string
  /** Description of what the tool does (shown to LLM) */
  description: string
  /** Zod schema for validating input */
  inputSchema: z.ZodSchema
  /** Zod schema for validating output */
  outputSchema: z.ZodSchema
  /** Integration adapter type (e.g., 'gmail', 'slack') */
  integration: T
  /** Method to call on the integration adapter (type-safe based on integration) */
  method: T extends keyof IntegrationMethodMap ? IntegrationMethodMap[T] : string
  /** Credential name to use from credentials table (e.g., 'support-gmail', 'sales-gmail') */
  credentialName: string
  /** Optional callback executed after successful tool execution (e.g., cache updates) - receives full options including iterationContext for memory management */
  onSuccess?: (result: unknown, options: ToolExecutionOptions) => void | Promise<void>
}

/**
 * Create an integration tool that calls external APIs using organization credentials
 *
 * Integration tools enable agents to interact with external services (Gmail, Slack, etc.)
 * using encrypted credentials stored in the credentials table. Each tool
 * specifies which credential name to use, allowing multiple credentials per integration type.
 *
 * @param config - Configuration for the integration tool
 * @returns Tool that calls the integration adapter with credentials
 *
 * @example
 * // Create tool for sending email via support Gmail account
 * import { EmailSchema } from '@repo/core'
 * const sendSupportEmail = createIntegrationTool({
 *   name: 'send_support_email',
 *   description: 'Send email from support@company.com',
 *   inputSchema: z.object({
 *     to: EmailSchema,
 *     subject: z.string(),
 *     body: z.string()
 *   }),
 *   outputSchema: z.object({ messageId: z.string() }),
 *   integration: 'gmail',
 *   method: 'sendEmail',
 *   credentialName: 'support-gmail'
 * })
 *
 * @example
 * // Create tool for sending email via sales Gmail account
 * import { EmailSchema } from '@repo/core'
 * const sendSalesEmail = createIntegrationTool({
 *   name: 'send_sales_email',
 *   description: 'Send email from sales@company.com',
 *   inputSchema: z.object({
 *     to: EmailSchema,
 *     subject: z.string(),
 *     body: z.string()
 *   }),
 *   outputSchema: z.object({ messageId: z.string() }),
 *   integration: 'gmail',
 *   method: 'sendEmail',
 *   credentialName: 'sales-gmail'  // Different credential, same integration
 * })
 */
export function createIntegrationTool(config: IntegrationToolConfig): Tool {
  return {
    name: config.name,
    description: config.description,
    inputSchema: config.inputSchema,
    outputSchema: config.outputSchema,

    async execute(options: ToolExecutionOptions): Promise<unknown> {
      // Get integration service from global registry
      const { integrationService } = getToolServices()
      if (!integrationService) {
        throw new ToolingError(
          'service_unavailable',
          'IntegrationService not initialized. Ensure toolServicesRegistry.initialize() was called in apps/api/src/main.ts',
          { integration: config.integration, method: config.method }
        )
      }

      // Call integration service
      const result = await integrationService.call(
        config.integration,
        config.method,
        options.input,
        config.credentialName,
        options.executionContext
      )

      // Execute onSuccess hook if provided (e.g., for cache updates)
      if (config.onSuccess) {
        await config.onSuccess(result, options)
      }

      return result
    }
  }
}
