import type { Response } from "express"
import type { FileDiffContent } from "@codeflash-ai/code-suggester/build/src/types.js"
import { getEffectivePrivacyMode, prisma } from "@codeflash-ai/common"
import { AuthorizedUserReq, SubscriptionInfo } from "../types.js"
import {
  StagingStorageStrategyFactory,
  StagingStorageContext,
  StagingStorageEligibility,
} from "../staging/index.js"

export interface CreateStagingRequestBody {
  prCommentFields: Record<string, unknown>
  traceId: string
  baseBranch: string
  owner?: string
  repo?: string
  diffContents?: Record<string, FileDiffContent>
  originalLineProfiler?: string
  optimizedLineProfiler?: string
}

// Dependencies for testing
export interface CreateStagingDependencies {
  getEffectivePrivacyMode: typeof getEffectivePrivacyMode
}

let dependencies: CreateStagingDependencies = {
  getEffectivePrivacyMode,
}

// For testing - allow dependency injection
export function setCreateStagingDependencies(deps: Partial<CreateStagingDependencies>) {
  dependencies = { ...dependencies, ...deps }
}

export function resetCreateStagingDependencies() {
  dependencies = { getEffectivePrivacyMode }
}

export default async function createStagingReview(req: AuthorizedUserReq, res: Response) {
  const subscriptionInfo = req.subscriptionInfo
  const result = await saveStagingReview(req.body, req.userId, req.organizationId, subscriptionInfo)
  return res.status(result.status).json(result.data)
}

export async function saveStagingReview(
  body: Record<string, unknown>,
  userId: string,
  organizationId?: string | null,
  subscriptionInfo?: SubscriptionInfo,
): Promise<{ status: number; data: Record<string, unknown> }> {
  const {
    prCommentFields,
    traceId,
    baseBranch,
    owner,
    repo,
    diffContents,
    originalLineProfiler,
    optimizedLineProfiler,
  } = body as unknown as CreateStagingRequestBody

  // Validate required fields
  const validationError = validateRequiredFields(prCommentFields, traceId)
  if (validationError) {
    return { status: 400, data: { error: validationError } }
  }

  // Fetch effective privacy mode (checks org first if API key has org, otherwise user)
  const privacyMode = await dependencies.getEffectivePrivacyMode(userId, organizationId ?? null)

  // Determine tier: if org has subscription, use "enterprise", otherwise use user's tier
  let tier = subscriptionInfo?.tier ?? "free"
  if (organizationId) {
    const org = await prisma.organizations.findUnique({
      where: { id: organizationId },
      select: { subscription: true },
    })
    if (org?.subscription) {
      tier = "enterprise"
    }
  }

  // Determine storage strategy based on user tier, privacy mode, and git repo availability
  // When privacy mode is OFF (paused), data is saved as plain text for faster loading
  const eligibility: StagingStorageEligibility = {
    tier,
    hasGitRepo: !!owner && !!repo,
    owner,
    repo,
    privacyMode,
  }

  const strategy = StagingStorageStrategyFactory.getStrategy(eligibility)

  // Build storage context
  const context: StagingStorageContext = {
    userId,
    traceId,
    baseBranch,
    owner,
    repo,
    diffContents: diffContents ? new Map(Object.entries(diffContents)) : undefined,
    prCommentFields,
    metadata: body,
    originalLineProfiler,
    optimizedLineProfiler,
  }

  // Execute the storage strategy
  const result = await strategy.save(context)

  if (!result.success) {
    let statusCode = 500
    const errorLower = result.error?.toLowerCase() ?? ""
    if (
      errorLower.includes("not found") ||
      (errorLower.includes("no ") && errorLower.includes("found"))
    ) {
      statusCode = 404
    } else if (result.error?.includes("Invalid") || result.error?.includes("Missing")) {
      statusCode = 400
    }
    return { status: statusCode, data: { error: result.error } }
  }

  const responseData: Record<string, unknown> = {
    message: "staging created successfully",
    storageType: result.storageType,
  }

  if (result.branchName) {
    responseData.branchName = result.branchName
  }

  return { status: 200, data: responseData }
}

// Helper functions
function validateRequiredFields(prCommentFields: unknown, traceId: unknown): string | null {
  if (!prCommentFields) {
    return "Missing prCommentFields in request body"
  }

  const fields = prCommentFields as Record<string, unknown>
  if (!fields.function_name || !fields.speedup_x || !traceId) {
    return "Missing required fields: function_name, speedup_x, and traceId"
  }

  return null
}
