import { ToolingError } from '../../../../../../types'
import type { ExecutionContext } from '../../../../../../../base/types'
import { withRetry, DEFAULT_RETRY_POLICY } from '../../../../../../../../../platform/resilience'
import type { SignatureApiCredentials, CreateEnvelopeParams, CreateEnvelopeResult } from '../utils/types'

const DEFAULT_API_URL = 'https://api.signatureapi.com/v1'

/**
 * Create a signature envelope via SignatureAPI
 *
 * @param credentials - SignatureAPI credentials (apiKey, optional apiUrl)
 * @param params - Envelope parameters (title, documents, recipients)
 * @param context - Execution context for logging
 * @returns Envelope ID and status
 * @throws ToolingError if creation fails
 */
export async function createEnvelope(
  credentials: SignatureApiCredentials,
  params: CreateEnvelopeParams,
  context?: ExecutionContext
): Promise<CreateEnvelopeResult> {
  const { apiKey, apiUrl = DEFAULT_API_URL } = credentials
  const { title, message, documents, recipients, metadata, webhookUrl, routing } = params

  // Validate credentials
  if (!apiKey) {
    throw new ToolingError('credentials_invalid', 'SignatureAPI credentials must include apiKey', {
      integration: 'signature-api',
      method: 'createEnvelope'
    })
  }

  // Validate required params
  if (!title || !documents?.length || !recipients?.length) {
    throw new ToolingError('validation_error', 'Title, documents, and recipients are required', {
      integration: 'signature-api',
      method: 'createEnvelope'
    })
  }

  // Map field types from our convenience types to SignatureAPI types
  // SignatureAPI does NOT support 'date' - must use 'recipient_completed_date'
  const mapFieldType = (type: string): string => {
    if (type === 'date') return 'recipient_completed_date'
    return type
  }

  // Standard page height for Letter size (792 points)
  // SignatureAPI uses 'top' (from top of page) instead of 'y' (from bottom)
  const PAGE_HEIGHT = 792

  // Convert y (from bottom) to top (from top)
  const yToTop = (y: number): number => PAGE_HEIGHT - y

  // Build request body
  // SignatureAPI requires separate arrays:
  // - fixed_positions: coordinates with place_key
  // - places: field definitions with key that matches place_key
  let placeCounter = 0
  const requestBody: Record<string, unknown> = {
    title,
    documents: documents.map((doc) => {
      // Build fixed_positions and places arrays from our places data
      const fixedPositions: Array<{
        place_key: string
        page: number
        top: number
        left: number
      }> = []

      const places: Array<{
        key: string
        type: string
        recipient_key: string
        font_color?: string
      }> = []

      doc.places?.forEach((place) => {
        const placeKey = `place_${placeCounter++}`

        // Fixed position (coordinates)
        fixedPositions.push({
          place_key: placeKey,
          page: place.page,
          top: yToTop(place.y), // Convert y (from bottom) to top (from top)
          left: place.x
        })

        // Place definition (field type, recipient, and optional styling)
        const placeObj: {
          key: string
          type: string
          recipient_key: string
          font_color?: string
        } = {
          key: placeKey,
          type: mapFieldType(place.type),
          recipient_key: place.recipientKey
        }

        // Add font color if specified
        if (place.fontColor) {
          placeObj.font_color = place.fontColor
        }

        places.push(placeObj)
      })

      return {
        url: doc.url,
        name: doc.name,
        fixed_positions: fixedPositions,
        places
      }
    }),
    recipients: recipients.map((r) => ({
      key: r.key,
      type: r.type,
      name: r.name,
      email: r.email,
      language: r.language,
      // Use manual ceremony creation so we get the signing URL back
      // and can send the email via our own system (Resend)
      ceremony_creation: 'manual'
    }))
  }

  if (message) requestBody.message = message
  if (metadata) requestBody.metadata = metadata
  if (webhookUrl) requestBody.webhook_url = webhookUrl
  if (routing) requestBody.routing = routing

  try {
    // Debug: Log the request structure
    const debugBody = {
      ...requestBody,
      documents: (
        requestBody.documents as Array<{
          name: string
          url: string
          fixed_positions: unknown[]
          places: unknown[]
        }>
      ).map((d) => ({
        name: d.name,
        url: d.url,
        fixed_positions: d.fixed_positions,
        places: d.places
      }))
    }
    context?.logger?.info(`[SignatureAPI] Request structure: ${JSON.stringify(debugBody, null, 2)}`)

    const response = await withRetry(async () => {
      const res = await fetch(`${apiUrl}/envelopes`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-API-Key': apiKey
        },
        body: JSON.stringify(requestBody)
      })

      if (!res.ok) {
        // Read body once and log it, then create error manually
        const errorBody = await res.text()
        context?.logger?.error(`[SignatureAPI] Error response: ${res.status} ${errorBody}`)

        // Parse error message from response
        let message = `signature-api API error: ${res.status}`
        try {
          const json = JSON.parse(errorBody)
          if (json.message) message = json.message
          else if (json.error?.message) message = json.error.message
          else if (json.errors?.[0]?.message) message = json.errors[0].message
          else if (errorBody.length < 1000) message = `signature-api ${res.status}: ${errorBody}`
        } catch {
          if (errorBody && errorBody.length < 1000) message = `signature-api ${res.status}: ${errorBody}`
        }

        throw new ToolingError('validation_error', message, {
          integration: 'signature-api',
          method: 'createEnvelope',
          statusCode: res.status,
          organizationId: context?.organizationId
        })
      }

      return res
    }, DEFAULT_RETRY_POLICY)

    const result = await response.json()

    // Log full response for debugging
    context?.logger?.info(`[SignatureApiAdapter] Full API response: ${JSON.stringify(result, null, 2)}`)

    // Log success
    if (context?.logger) {
      context.logger.info(
        `[SignatureApiAdapter] Envelope created: organizationId=${context.organizationId} executionId=${context.executionId} envelopeId=${result.id}`
      )
    }

    // With ceremony_creation: 'manual', we need to create the ceremony separately
    // to get the signing URL. The ceremony is NOT created automatically.
    let signingUrl = ''
    const recipientId = result.recipients?.[0]?.id

    if (recipientId) {
      context?.logger?.info(`[SignatureApiAdapter] Creating ceremony for recipient: ${recipientId}`)

      try {
        // Ceremony creation requires authentication configuration
        // Using 'custom' auth means we handle verification ourselves (via our proposal workflow)
        // The recipient clicks the URL and goes directly to signing - no code needed
        // This works even in SignatureAPI test mode since no emails are sent by SignatureAPI
        const recipientEmail = recipients[0]?.email || 'unknown'
        const ceremonyBody = {
          authentication: [
            {
              type: 'custom',
              provider: 'Elevasis',
              data: {
                verified_via: 'proposal_workflow',
                email: recipientEmail,
                timestamp: new Date().toISOString()
              }
            }
          ]
        }

        const ceremonyResponse = await fetch(`${apiUrl}/recipients/${recipientId}/ceremonies`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'X-API-Key': apiKey
          },
          body: JSON.stringify(ceremonyBody)
        })

        if (ceremonyResponse.ok) {
          const ceremony = await ceremonyResponse.json()
          signingUrl = ceremony.url || ''
          context?.logger?.info(`[SignatureApiAdapter] Ceremony created, signing URL available: ${!!signingUrl}`)
        } else {
          const ceremonyError = await ceremonyResponse.text()
          context?.logger?.error(
            `[SignatureApiAdapter] Failed to create ceremony: ${ceremonyResponse.status} ${ceremonyError}`
          )
        }
      } catch (ceremonyError) {
        context?.logger?.error(`[SignatureApiAdapter] Error creating ceremony: ${ceremonyError}`)
      }
    } else {
      context?.logger?.warn('[SignatureApiAdapter] No recipient ID in response - cannot create ceremony')
    }

    return {
      id: result.id,
      status: result.status,
      signingUrl
    }
  } catch (error) {
    if (error instanceof ToolingError) {
      throw error
    }

    throw new ToolingError('api_error', `Failed to create envelope: ${(error as Error).message}`, {
      integration: 'signature-api',
      method: 'createEnvelope',
      organizationId: context?.organizationId,
      originalError: error
    })
  }
}
