import { z } from 'zod'
import { TRPCError } from '@trpc/server'
import { Prisma } from '@prisma/client'
import { router, adminProcedure } from '../trpc'
import {
  testTypeformConnection,
  getTypeformSchema,
  getAllTypeformResponses,
  responseToObject,
} from '@/lib/typeform'
import { normalizeCountryToCode } from '@/lib/countries'

export const typeformImportRouter = router({
  /**
   * Test connection to Typeform API
   */
  testConnection: adminProcedure
    .input(
      z.object({
        apiKey: z.string().min(1),
      })
    )
    .mutation(async ({ input }) => {
      return testTypeformConnection(input.apiKey)
    }),

  /**
   * Get form schema (questions/fields) for mapping
   */
  getFormSchema: adminProcedure
    .input(
      z.object({
        apiKey: z.string().min(1),
        formId: z.string().min(1),
      })
    )
    .query(async ({ input }) => {
      try {
        return await getTypeformSchema(input.apiKey, input.formId)
      } catch (error) {
        throw new TRPCError({
          code: 'BAD_REQUEST',
          message:
            error instanceof Error
              ? error.message
              : 'Failed to fetch form schema',
        })
      }
    }),

  /**
   * Preview responses from Typeform
   */
  previewResponses: adminProcedure
    .input(
      z.object({
        apiKey: z.string().min(1),
        formId: z.string().min(1),
        limit: z.number().int().min(1).max(10).default(5),
      })
    )
    .query(async ({ input }) => {
      try {
        const schema = await getTypeformSchema(input.apiKey, input.formId)
        const responses = await getAllTypeformResponses(
          input.apiKey,
          input.formId,
          input.limit
        )

        // Convert responses to flat objects for preview
        const records = responses.map((r) => responseToObject(r, schema.fields))

        return {
          records,
          count: records.length,
          formTitle: schema.title,
        }
      } catch (error) {
        throw new TRPCError({
          code: 'BAD_REQUEST',
          message:
            error instanceof Error
              ? error.message
              : 'Failed to fetch responses from Typeform',
        })
      }
    }),

  /**
   * Import projects from Typeform responses
   */
  importProjects: adminProcedure
    .input(
      z.object({
        apiKey: z.string().min(1),
        formId: z.string().min(1),
        programId: z.string(),
        mappings: z.object({
          title: z.string(),
          teamName: z.string().optional(),
          description: z.string().optional(),
          tags: z.string().optional(),
          email: z.string().optional(),
          country: z.string().optional(),
        }),
        includeUnmappedInMetadata: z.boolean().default(true),
      })
    )
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.program.findUniqueOrThrow({
        where: { id: input.programId },
      })

      // Fetch form schema and all responses
      const schema = await getTypeformSchema(input.apiKey, input.formId)
      const responses = await getAllTypeformResponses(input.apiKey, input.formId)

      if (responses.length === 0) {
        return { imported: 0, skipped: 0, errors: [] }
      }

      const results = {
        imported: 0,
        skipped: 0,
        errors: [] as Array<{ responseId: string; error: string }>,
      }

      // Process each response
      for (const response of responses) {
        try {
          const record = responseToObject(response, schema.fields)

          // Get mapped values
          const title = record[input.mappings.title]

          if (!title || typeof title !== 'string' || !title.trim()) {
            results.errors.push({
              responseId: response.response_id,
              error: 'Missing or invalid title',
            })
            results.skipped++
            continue
          }

          const teamName = input.mappings.teamName
            ? record[input.mappings.teamName]
            : null

          const description = input.mappings.description
            ? record[input.mappings.description]
            : null

          let tags: string[] = []
          if (input.mappings.tags) {
            const tagsValue = record[input.mappings.tags]
            if (Array.isArray(tagsValue)) {
              tags = tagsValue.filter((t): t is string => typeof t === 'string')
            } else if (typeof tagsValue === 'string') {
              tags = tagsValue.split(',').map((t) => t.trim()).filter(Boolean)
            }
          }

          // Get country and normalize to ISO code
          let country: string | null = null
          if (input.mappings.country) {
            const countryValue = record[input.mappings.country]
            if (typeof countryValue === 'string') {
              country = normalizeCountryToCode(countryValue)
            }
          }

          // Build metadata from unmapped columns
          let metadataJson: Record<string, unknown> | null = null
          if (input.includeUnmappedInMetadata) {
            const mappedKeys = new Set([
              input.mappings.title,
              input.mappings.teamName,
              input.mappings.description,
              input.mappings.tags,
              input.mappings.email,
              input.mappings.country,
              '_response_id',
              '_submitted_at',
            ].filter(Boolean))

            metadataJson = {}
            for (const [key, value] of Object.entries(record)) {
              if (!mappedKeys.has(key) && value !== null && value !== undefined) {
                metadataJson[key] = value
              }
            }

            // Add submission email if mapped
            if (input.mappings.email) {
              const email = record[input.mappings.email]
              if (email) {
                metadataJson._submissionEmail = email
              }
            }

            // Add submission timestamp
            metadataJson._submittedAt = response.submitted_at

            if (Object.keys(metadataJson).length === 0) {
              metadataJson = null
            }
          }

          // Create project
          await ctx.prisma.project.create({
            data: {
              programId: input.programId,
              status: 'SUBMITTED',
              title: String(title).trim(),
              teamName: typeof teamName === 'string' ? teamName.trim() : null,
              description: typeof description === 'string' ? description : null,
              tags,
              country,
              metadataJson: metadataJson as Prisma.InputJsonValue ?? undefined,
              externalIdsJson: {
                typeformResponseId: response.response_id,
                typeformFormId: input.formId,
              } as Prisma.InputJsonValue,
            },
          })

          results.imported++
        } catch (error) {
          results.errors.push({
            responseId: response.response_id,
            error: error instanceof Error ? error.message : 'Unknown error',
          })
          results.skipped++
        }
      }

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'IMPORT',
          entityType: 'Project',
          detailsJson: {
            source: 'typeform',
            formId: input.formId,
            imported: results.imported,
            skipped: results.skipped,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return results
    }),
})
