"use server"

import { CF_API } from "@/app/api/const"
import { ActionResponse, createErrorResponse, createSuccessResponse } from "@/lib/action-response"
import { getRepositoriesForAccountCached } from "@/lib/services/repository-utils"
import { getAccessToken } from "@auth0/nextjs-auth0"
import { AccountPayload, buildOptimizationOrCondition, prisma } from "@codeflash-ai/common"
import * as Sentry from "@sentry/nextjs"

export interface DiffContent {
  oldContent: string
  newContent: string
}

export interface StagingCodeResponse {
  storageType: "git_branch"
  diffContents: Record<string, DiffContent>
  stagingBranchName: string
  baseBranch: string | null
  functionName: string | null
  filePath: string | null
}

export interface GetStagingCodeParams {
  stagingBranchName: string
  baseBranch: string
  fullRepoName: string
  installationId: number
  functionName?: string
  filePath?: string
}

export async function getStagingCodeFromApi(params: GetStagingCodeParams): Promise<ActionResponse<StagingCodeResponse>> {
  const cfapiUrl = process.env.CODEFLASH_CFAPI_URL
  const session = await getAccessToken({ refresh: true })

  if (!cfapiUrl || !session?.accessToken) {
    return createErrorResponse("Please sign in to continue")
  }

  try {
    const response = await fetch(`${cfapiUrl}/${CF_API}/get-staging-code`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${session.accessToken}`,
        "X-CodeFlash-Source": "webapp",
      },
      body: JSON.stringify(params),
    })

    if (!response.ok) {
      const contentType = response.headers.get("content-type")
      let errorMessage = "Failed to fetch staging code"

      if (contentType?.includes("json")) {
        const error = await response.json()
        errorMessage = error.error || error.message || errorMessage
      } else {
        const text = await response.text()
        if (text) errorMessage = text
      }

      if (response.status === 403) {
        return createErrorResponse("You are not a collaborator on this repository")
      }
      if (response.status === 404) {
        return createErrorResponse("Staging code not found")
      }

      return createErrorResponse(errorMessage)
    }

    const data = await response.json()
    return createSuccessResponse(data as StagingCodeResponse)
  } catch (error: any) {
    console.error("[getStagingCodeFromApi] Error:", error)
    Sentry.captureException(error)
    return createErrorResponse(error?.message || "Failed to fetch staging code")
  }
}

export interface CommitStagingCodeResponse {
  message: string
  commitSha: string
  stagingBranchName: string
}

export async function commitStagingCode(
  traceId: string,
  fileChanges: Record<string, string>,
  commitMessage?: string,
): Promise<ActionResponse<CommitStagingCodeResponse>> {
  const cfapiUrl = process.env.CODEFLASH_CFAPI_URL
  const session = await getAccessToken({ refresh: true })

  if (!cfapiUrl || !session?.accessToken) {
    return createErrorResponse("Please sign in to continue")
  }

  try {
    const response = await fetch(`${cfapiUrl}/${CF_API}/commit-staging-code`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${session.accessToken}`,
        "X-CodeFlash-Source": "webapp",
      },
      body: JSON.stringify({
        traceId,
        fileChanges,
        commitMessage,
      }),
    })

    if (!response.ok) {
      const contentType = response.headers.get("content-type")
      let errorMessage = "Failed to commit changes"

      if (contentType?.includes("json")) {
        const error = await response.json()
        errorMessage = error.error || error.message || errorMessage
      } else {
        const text = await response.text()
        if (text) errorMessage = text
      }

      if (response.status === 403) {
        return createErrorResponse("You are not a collaborator on this repository")
      }
      if (response.status === 404) {
        return createErrorResponse("Staging branch not found")
      }

      return createErrorResponse(errorMessage)
    }

    const data = await response.json()
    return createSuccessResponse(data as CommitStagingCodeResponse)
  } catch (error: any) {
    console.error("[commitStagingCode] Error:", error)
    Sentry.captureException(error)
    return createErrorResponse(error?.message || "Failed to commit changes")
  }
}

export async function getOptimizationEventById({
  payload,
  trace_id,
}: {
  payload: AccountPayload
  trace_id: string
}) {
  const repoIds = (await getRepositoriesForAccountCached(payload)).repoIds
  const where: any = {
    trace_id,
    ...buildOptimizationOrCondition(payload, repoIds),
  }
  const event = await prisma.optimization_events.findFirst({
    where,
    include: {
      repository: true,
    },
  })

  if (event) {
    // Fetch review_quality and review_explanation from optimization_features
    const features = await prisma.optimization_features.findUnique({
      where: { trace_id: event.trace_id },
      select: {
        review_quality: true,
        review_explanation: true,
      },
    })

    return {
      ...event,
      review_quality: features?.review_quality || null,
      review_explanation: features?.review_explanation || null,
    }
  }

  return event
}
export async function saveOptimizationChanges({
  eventId,
  filePath,
  newContent,
}: {
  userId: string
  eventId: string
  filePath: string
  newContent: string
}) {
  try {
    const currentEvent = await prisma.optimization_events.findUnique({
      where: {
        id: eventId,
      },
    })

    if (!currentEvent) {
      throw new Error("Event not found")
    }

    // Get the current metadata
    const currentMetadata = (currentEvent.metadata as any) || {}
    const currentDiffContents = currentMetadata.diffContents || {}

    // Update only the specific file's content
    const updatedDiffContents = {
      ...currentDiffContents,
      [filePath]: {
        ...currentDiffContents[filePath],
        newContent: newContent,
      },
    }

    // Update the metadata with new diff contents
    const updatedMetadata = {
      ...currentMetadata,
      diffContents: updatedDiffContents,
      lastModified: new Date().toISOString(),
    }

    // Save to database
    const updatedEvent = await prisma.optimization_events.update({
      where: {
        id: eventId,
      },
      data: {
        metadata: updatedMetadata,
      },
    })

    return { success: true, event: updatedEvent }
  } catch (error) {
    console.error("Error saving optimization changes:", error)
    return {
      success: false,
      error: error instanceof Error ? error.message : "Failed to save changes",
    }
  }
}

export async function createPullRequest({
  traceId,
  diffContents,
  prCommentFields,
  generatedTests,
  existingTests,
  functionName,
  filePath,
  speedupX,
  speedupPct,
  baseBranch,
  full_repo_name,
  coverage_message,
  originalLineProfiler,
  optimizedLineProfiler,
}: {
  traceId: string
  diffContents: Record<string, { oldContent: string; newContent: string }>
  prCommentFields?: any
  generatedTests?: string
  existingTests?: string
  functionName?: string
  filePath?: string
  speedupX?: string
  speedupPct?: string
  baseBranch?: string
  full_repo_name?: string
  coverage_message?: string
  originalLineProfiler?: string
  optimizedLineProfiler?: string
}): Promise<ActionResponse> {
  const cfapiUrl = process.env.CODEFLASH_CFAPI_URL
  const session = await getAccessToken({ refresh: true })

  if (!cfapiUrl || !session?.accessToken) {
    return createErrorResponse("Please sign in to continue")
  }

  const [owner, repoName] = full_repo_name?.split("/") ?? []
  if (!owner || !repoName) {
    return createErrorResponse("Invalid repository name")
  }

  try {
    const response = await fetch(`${cfapiUrl}/${CF_API}/create-pr`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${session.accessToken}`,
        "X-CodeFlash-Source": "webapp",
      },
      body: JSON.stringify({
        traceId,
        diffContents,
        prCommentFields: {
          ...prCommentFields,
          function_name: functionName,
          file_path: filePath,
          speedup_x: speedupX,
          speedup_pct: speedupPct,
        },
        generatedTests,
        existingTests,
        coverage_message,
        baseBranch,
        owner,
        repo: repoName,
        originalLineProfiler,
        optimizedLineProfiler,
      }),
    })

    if (response.ok || response.status === 202) {
      const contentType = response.headers.get("content-type")
      if (contentType?.includes("json")) {
        const data = await response.json()
        console.log("[createPullRequest] Success response from API:", {
          status: response.status,
          data,
          dataType: typeof data,
        })
        return createSuccessResponse(data)
      }
      const data = await response.text()
      console.log("[createPullRequest] Success response from API (text):", {
        status: response.status,
        data,
        dataType: typeof data,
      })
      return createSuccessResponse(data)
    }

    // Get error message from response
    let errorMessage = "Failed to create pull request"

    const contentType = response.headers.get("content-type")
    if (contentType?.includes("json")) {
      const error = await response.json()
      errorMessage = error.message || error.error || errorMessage
    } else if (contentType?.includes("html")) {
      // HTML error page - provide a meaningful message based on status
      if (response.status === 404) {
        errorMessage = "API endpoint not found. Please check if the API server is running."
      } else if (response.status === 502 || response.status === 503) {
        errorMessage = "API server is unavailable. Please try again later."
      } else {
        errorMessage = `Server error (${response.status}). Please try again later.`
      }
    } else {
      const text = await response.text()
      if (text && !text.includes("<!DOCTYPE") && !text.includes("<html")) {
        errorMessage = text
      }
    }

    // Log to Sentry
    Sentry.captureException(new Error(errorMessage), {
      extra: {
        status: response.status,
        traceId,
        owner,
        repo: repoName,
      },
    })

    return createErrorResponse(errorMessage)
  } catch (error: any) {
    const errorMessage = error?.message || "Something went wrong. Please try again."
    Sentry.captureException(error)
    return createErrorResponse(errorMessage)
  }
}

export async function setApprovalStatus(eventId: string, status: "approved" | "rejected") {
  try {
    const updated = await prisma.optimization_events.update({
      where: {
        id: eventId,
      },
      data: {
        status,
      },
    })
    return { success: true, event: updated }
  } catch (error) {
    console.error(`Error setting approval status to ${status}:`, error)
    return { success: false, error: error instanceof Error ? error.message : "Unknown error" }
  }
}

export async function addComment({
  eventId,
  userId,
  content,
}: {
  eventId: string
  userId: string
  content: string
}) {
  try {
    const comment = await prisma.comments.create({
      data: {
        optimization_event_id: eventId,
        author_user_id: userId,
        content,
      },
    })
    return { success: true, comment }
  } catch (error) {
    console.error("Error adding comment:", error)
    return {
      success: false,
      error: error instanceof Error ? error.message : "Failed to add comment",
    }
  }
}

export async function getCommentsByEvent(eventId: string) {
  try {
    const comments = await prisma.comments.findMany({
      where: {
        optimization_event_id: eventId,
      },
      orderBy: {
        created_at: "asc",
      },
      include: {
        author: {
          select: {
            user_id: true,
            email: true,
            name: true,
            github_username: true,
          },
        },
      },
    })

    return { success: true, comments }
  } catch (error) {
    console.error("Error fetching comments:", error)
    return {
      success: false,
      error: error instanceof Error ? error.message : "Failed to fetch comments",
    }
  }
}
