import { db } from '@sim/db'
import {
  templateCreators,
  templateStars,
  templates,
  workflow,
  workflowDeploymentVersion,
} from '@sim/db/schema'
import { createLogger } from '@sim/logger'
import { and, desc, eq, ilike, or, sql } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log'
import { getSession } from '@/lib/auth'
import { generateRequestId } from '@/lib/core/utils/request'
import { generateId } from '@/lib/core/utils/uuid'
import { canAccessTemplate, verifyEffectiveSuperUser } from '@/lib/templates/permissions'
import {
  extractRequiredCredentials,
  sanitizeCredentials,
} from '@/lib/workflows/credentials/credential-extractor'
import { authorizeWorkflowByWorkspacePermission } from '@/lib/workflows/utils'

const logger = createLogger('TemplatesAPI')

export const revalidate = 0

// Function to sanitize sensitive data from workflow state
// Now uses the more comprehensive sanitizeCredentials from credential-extractor
function sanitizeWorkflowState(state: any): any {
  return sanitizeCredentials(state)
}

// Schema for creating a template
const CreateTemplateSchema = z.object({
  workflowId: z.string().min(1, 'Workflow ID is required'),
  name: z.string().min(1, 'Name is required').max(100, 'Name must be less than 100 characters'),
  details: z
    .object({
      tagline: z.string().max(500, 'Tagline must be less than 500 characters').optional(),
      about: z.string().optional(), // Markdown long description
    })
    .optional(),
  creatorId: z.string().min(1, 'Creator profile is required'),
  tags: z.array(z.string()).max(10, 'Maximum 10 tags allowed').optional().default([]),
})

// Schema for query parameters
const QueryParamsSchema = z.object({
  limit: z.coerce.number().optional().default(50),
  offset: z.coerce.number().optional().default(0),
  search: z.string().optional(),
  workflowId: z.string().optional(),
  status: z.enum(['pending', 'approved', 'rejected']).optional(),
  includeAllStatuses: z.coerce.boolean().optional().default(false), // For super users
})

// GET /api/templates - Retrieve templates
export async function GET(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 { searchParams } = new URL(request.url)
    const params = QueryParamsSchema.parse(Object.fromEntries(searchParams.entries()))

    // 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 = 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: any) {
    if (error instanceof z.ZodError) {
      logger.warn(`[${requestId}] Invalid query parameters`, { errors: error.errors })
      return NextResponse.json(
        { error: 'Invalid query parameters', details: error.errors },
        { status: 400 }
      )
    }

    logger.error(`[${requestId}] Error fetching templates`, error)
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
}

// POST /api/templates - Create a new template
export async function POST(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 body = await request.json()
    const data = CreateTemplateSchema.parse(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 any
    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 || 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}"`,
      request,
    })

    return NextResponse.json(
      {
        id: templateId,
        message: 'Template submitted for approval successfully',
      },
      { status: 201 }
    )
  } catch (error: any) {
    if (error instanceof z.ZodError) {
      logger.warn(`[${requestId}] Invalid template data`, { errors: error.errors })
      return NextResponse.json(
        { error: 'Invalid template data', details: error.errors },
        { status: 400 }
      )
    }

    logger.error(`[${requestId}] Error creating template`, error)
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
  }
}
