import { AuditAction, AuditResourceType, recordAudit } from '@sim/audit'
import { db } from '@sim/db'
import {
  templateCreators,
  templateStars,
  templates,
  workflow,
  workflowDeploymentVersion,
} from '@sim/db/schema'
import { createLogger } from '@sim/logger'
import { generateId } from '@sim/utils/id'
import { authorizeWorkflowByWorkspacePermission } from '@sim/workflow-authz'
import { and, desc, eq, ilike, or, sql } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { createTemplateContract, listTemplatesContract } from '@/lib/api/contracts/templates'
import { parseRequest } from '@/lib/api/server'
import { getSession } from '@/lib/auth'
import { generateRequestId } from '@/lib/core/utils/request'
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
import { canAccessTemplate, verifyEffectiveSuperUser } from '@/lib/templates/permissions'
import {
  extractRequiredCredentials,
  sanitizeCredentials,
} from '@/lib/workflows/credentials/credential-extractor'
import type { WorkflowState } from '@/stores/workflows/workflow/types'

const logger = createLogger('TemplatesAPI')

export const revalidate = 0

function sanitizeWorkflowState(state: Partial<WorkflowState> | null | undefined): unknown {
  return sanitizeCredentials(state)
}

// GET /api/templates - Retrieve templates
export const GET = withRouteHandler(async (request: NextRequest) => {
  const requestId = generateRequestId()

  try {
    const session = await getSession()
    if (!session?.user?.id) {
      logger.warn(`[${requestId}] Unauthorized templates access attempt`)
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const parsed = await parseRequest(listTemplatesContract, request, {})
    if (!parsed.success) return parsed.response
    const params = parsed.data.query

    // Check if user is a super user
    const { effectiveSuperUser } = await verifyEffectiveSuperUser(session.user.id)
    const isSuperUser = effectiveSuperUser

    // Build query conditions
    const conditions = []

    // Apply workflow filter if provided (for getting template by workflow)
    // When fetching by workflowId, we want to get the template regardless of status
    // This is used by the deploy modal to check if a template exists
    if (params.workflowId) {
      const authorization = await authorizeWorkflowByWorkspacePermission({
        workflowId: params.workflowId,
        userId: session.user.id,
        action: 'write',
      })
      if (!authorization.allowed) {
        return NextResponse.json(
          {
            data: [],
            pagination: {
              total: 0,
              limit: params.limit,
              offset: params.offset,
              page: 1,
              totalPages: 0,
            },
          },
          { status: 200 }
        )
      }
      conditions.push(eq(templates.workflowId, params.workflowId))
    } else {
      // Apply status filter - only approved templates for non-super users
      if (params.status) {
        if (!isSuperUser && params.status !== 'approved') {
          return NextResponse.json(
            {
              data: [],
              pagination: {
                total: 0,
                limit: params.limit,
                offset: params.offset,
                page: 1,
                totalPages: 0,
              },
            },
            { status: 200 }
          )
        }
        conditions.push(eq(templates.status, params.status))
      } else if (!isSuperUser || !params.includeAllStatuses) {
        // Non-super users and super users without includeAllStatuses flag see only approved templates
        conditions.push(eq(templates.status, 'approved'))
      }
    }

    // Apply search filter if provided
    if (params.search) {
      const searchTerm = `%${params.search}%`
      conditions.push(
        or(
          ilike(templates.name, searchTerm),
          sql`${templates.details}->>'tagline' ILIKE ${searchTerm}`
        )
      )
    }

    // Combine conditions
    const whereCondition = conditions.length > 0 ? and(...conditions) : undefined

    // Apply ordering, limit, and offset with star information
    const results = await db
      .select({
        id: templates.id,
        workflowId: templates.workflowId,
        name: templates.name,
        details: templates.details,
        creatorId: templates.creatorId,
        creator: templateCreators,
        views: templates.views,
        stars: templates.stars,
        status: templates.status,
        tags: templates.tags,
        requiredCredentials: templates.requiredCredentials,
        state: templates.state,
        createdAt: templates.createdAt,
        updatedAt: templates.updatedAt,
        isStarred: sql<boolean>`CASE WHEN ${templateStars.id} IS NOT NULL THEN true ELSE false END`,
        isSuperUser: sql<boolean>`${isSuperUser}`, // Include super user status in response
      })
      .from(templates)
      .leftJoin(
        templateStars,
        and(eq(templateStars.templateId, templates.id), eq(templateStars.userId, session.user.id))
      )
      .leftJoin(templateCreators, eq(templates.creatorId, templateCreators.id))
      .where(whereCondition)
      .orderBy(desc(templates.views), desc(templates.createdAt))
      .limit(params.limit)
      .offset(params.offset)

    // Get total count for pagination
    const totalCount = await db
      .select({ count: sql<number>`count(*)` })
      .from(templates)
      .where(whereCondition)

    const total = Number(totalCount[0]?.count ?? 0)

    const visibleResults =
      params.workflowId && !isSuperUser
        ? (
            await Promise.all(
              results.map(async (template) => {
                if (template.status === 'approved') {
                  return template
                }
                const access = await canAccessTemplate(template.id, session.user.id)
                return access.allowed ? template : null
              })
            )
          ).filter((template): template is (typeof results)[number] => template !== null)
        : results

    logger.info(`[${requestId}] Successfully retrieved ${visibleResults.length} templates`)

    return NextResponse.json({
      data: visibleResults,
      pagination: {
        total: params.workflowId && !isSuperUser ? visibleResults.length : total,
        limit: params.limit,
        offset: params.offset,
        page: Math.floor(params.offset / params.limit) + 1,
        totalPages: Math.ceil(
          (params.workflowId && !isSuperUser ? visibleResults.length : total) / params.limit
        ),
      },
    })
  } catch (error) {
    logger.error(`[${requestId}] Error fetching templates`, error)
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
})

// POST /api/templates - Create a new template
export const POST = withRouteHandler(async (request: NextRequest) => {
  const requestId = generateRequestId()

  try {
    const session = await getSession()
    if (!session?.user?.id) {
      logger.warn(`[${requestId}] Unauthorized template creation attempt`)
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
    }

    const parsed = await parseRequest(createTemplateContract, request, {})
    if (!parsed.success) return parsed.response
    const data = parsed.data.body

    const workflowAuthorization = await authorizeWorkflowByWorkspacePermission({
      workflowId: data.workflowId,
      userId: session.user.id,
      action: 'write',
    })

    if (!workflowAuthorization.workflow) {
      logger.warn(`[${requestId}] Workflow not found: ${data.workflowId}`)
      return NextResponse.json({ error: 'Workflow not found' }, { status: 404 })
    }

    if (!workflowAuthorization.allowed) {
      logger.warn(`[${requestId}] User denied permission to template workflow ${data.workflowId}`)
      return NextResponse.json(
        { error: workflowAuthorization.message || 'Access denied' },
        { status: workflowAuthorization.status || 403 }
      )
    }

    const { verifyCreatorPermission } = await import('@/lib/templates/permissions')
    const { hasPermission, error: permissionError } = await verifyCreatorPermission(
      session.user.id,
      data.creatorId,
      'member'
    )

    if (!hasPermission) {
      logger.warn(`[${requestId}] User cannot use creator profile: ${data.creatorId}`)
      return NextResponse.json({ error: permissionError || 'Access denied' }, { status: 403 })
    }

    const templateId = generateId()
    const now = new Date()

    // Get the active deployment version for the workflow to copy its state
    const activeVersion = await db
      .select({
        id: workflowDeploymentVersion.id,
        state: workflowDeploymentVersion.state,
      })
      .from(workflowDeploymentVersion)
      .where(
        and(
          eq(workflowDeploymentVersion.workflowId, data.workflowId),
          eq(workflowDeploymentVersion.isActive, true)
        )
      )
      .limit(1)

    if (activeVersion.length === 0) {
      logger.warn(
        `[${requestId}] No active deployment version found for workflow: ${data.workflowId}`
      )
      return NextResponse.json(
        { error: 'Workflow must be deployed before creating a template' },
        { status: 400 }
      )
    }

    // Ensure the state includes workflow variables (if not already included)
    let stateWithVariables = activeVersion[0].state as Partial<WorkflowState> | null | undefined
    if (stateWithVariables && !stateWithVariables.variables) {
      // Fetch workflow variables if not in deployment version
      const [workflowRecord] = await db
        .select({ variables: workflow.variables })
        .from(workflow)
        .where(eq(workflow.id, data.workflowId))
        .limit(1)

      stateWithVariables = {
        ...stateWithVariables,
        variables: (workflowRecord?.variables as WorkflowState['variables']) || undefined,
      }
    }

    // Extract credential requirements before sanitizing
    const requiredCredentials = extractRequiredCredentials(stateWithVariables)

    // Sanitize the workflow state to remove all credential values
    const sanitizedState = sanitizeWorkflowState(stateWithVariables)

    const newTemplate = {
      id: templateId,
      workflowId: data.workflowId,
      name: data.name,
      details: data.details || null,
      creatorId: data.creatorId,
      views: 0,
      stars: 0,
      status: 'pending' as const, // All new templates start as pending
      tags: data.tags || [],
      requiredCredentials: requiredCredentials, // Store the extracted credential requirements
      state: sanitizedState, // Store the sanitized state without credential values
      createdAt: now,
      updatedAt: now,
    }

    await db.insert(templates).values(newTemplate)

    logger.info(`[${requestId}] Successfully created template: ${templateId}`)

    recordAudit({
      actorId: session.user.id,
      actorName: session.user.name,
      actorEmail: session.user.email,
      action: AuditAction.TEMPLATE_CREATED,
      resourceType: AuditResourceType.TEMPLATE,
      resourceId: templateId,
      resourceName: data.name,
      description: `Created template "${data.name}"`,
      metadata: {
        templateName: data.name,
        workflowId: data.workflowId,
        creatorId: data.creatorId,
        tags: data.tags,
        tagline: data.details?.tagline || undefined,
        status: 'pending',
      },
      request,
    })

    return NextResponse.json(
      {
        id: templateId,
        message: 'Template submitted for approval successfully',
      },
      { status: 201 }
    )
  } catch (error) {
    logger.error(`[${requestId}] Error creating template`, error)
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
})
