"use client"

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"

import { ACCESS_TOKEN_REGEXP, API_URL } from "@shared/lib/constants"

export type WorkflowPhase =
	| "INGEST"
	| "VERIFY"
	| "SILENCE"
	| "TRANSCRIPTION"
	| "CAPTIONS"
	| "DONE"

export type WorkflowScreen =
	| "upload"
	| "verify"
	| "silence-settings"
	| "processing"
	| "fragments"
	| "silence-apply-processing"
	| "transcription-settings"
	| "transcription-processing"
	| "subtitle-revision"
	| "caption-settings"
	| "caption-processing"
	| "caption-result"

export interface SilenceSettingsPayload {
	min_silence_duration_ms: number
	silence_threshold_db: number
	padding_ms: number
}

export interface WorkflowCutRegionPayload {
	start_ms: number
	end_ms: number
}

export interface WorkflowActiveJob {
	job_id: string
	job_type: string
}

export interface WorkflowWorkspaceView {
	used_file_ids: string[]
	selected_file_id: string | null
}

export interface WorkflowSilenceState {
	status: string | null
	settings: SilenceSettingsPayload | null
	detect_job_id: string | null
	detected_segments: WorkflowCutRegionPayload[]
	reviewed_cuts: WorkflowCutRegionPayload[]
	duration_ms: number | null
	applied_output_file_id: string | null
}

export interface WorkflowTranscriptionRequest {
	engine: "whisper" | "google" | "salutespeech"
	language?: string
	model: string
}

export interface WorkflowTranscriptionState {
	status: string | null
	job_id: string | null
	request: WorkflowTranscriptionRequest | null
	artifact_id: string | null
	transcription_id: string | null
	reviewed: boolean
}

export interface WorkflowCaptionsState {
	status: string | null
	preset_id: string | null
	style_config: Record<string, unknown> | null
	render_job_id: string | null
	output_file_id: string | null
}

export interface ProjectWorkspaceRead {
	revision: number
	phase: WorkflowPhase
	current_screen: WorkflowScreen
	active_job: WorkflowActiveJob | null
	source_file_id: string | null
	workspace_view: WorkflowWorkspaceView
	silence: WorkflowSilenceState
	transcription: WorkflowTranscriptionState
	captions: WorkflowCaptionsState
}

type WorkflowActionBase<TActionType extends string> = {
	type: TActionType
	revision: number
}

export type WorkflowActionRequest =
	| (WorkflowActionBase<"SET_SOURCE_FILE"> & {
			file_id: string
	  })
	| WorkflowActionBase<"RESET_SOURCE_FILE">
	| (WorkflowActionBase<"START_MEDIA_CONVERT"> & {
			output_format?: "mp4"
	  })
	| WorkflowActionBase<"CONFIRM_VERIFY">
	| (WorkflowActionBase<"SET_SILENCE_SETTINGS"> & {
			settings: SilenceSettingsPayload
	  })
	| WorkflowActionBase<"START_SILENCE_DETECT">
	| (WorkflowActionBase<"SET_SILENCE_CUTS"> & {
			cuts: WorkflowCutRegionPayload[]
	  })
	| WorkflowActionBase<"SKIP_SILENCE_APPLY">
	| (WorkflowActionBase<"START_SILENCE_APPLY"> & {
			cuts: WorkflowCutRegionPayload[]
	  })
	| WorkflowActionBase<"REOPEN_SILENCE_REVIEW">
	| (WorkflowActionBase<"START_TRANSCRIPTION"> & {
			request: WorkflowTranscriptionRequest
	  })
	| WorkflowActionBase<"REOPEN_TRANSCRIPTION_CONFIG">
	| WorkflowActionBase<"MARK_TRANSCRIPTION_REVIEWED">
	| (WorkflowActionBase<"SELECT_CAPTION_PRESET"> & {
			preset_id: string | null
	  })
	| WorkflowActionBase<"START_CAPTION_RENDER">
	| WorkflowActionBase<"REOPEN_CAPTION_CONFIG">
	| (WorkflowActionBase<"SET_WORKSPACE_VIEW"> & {
			workspace_view: WorkflowWorkspaceView
	  })

class WorkflowApiError extends Error {
	status: number

	constructor(status: number, message: string) {
		super(message)
		this.name = "WorkflowApiError"
		this.status = status
	}
}

function getBaseApiUrl(): string {
	if (API_URL?.length) return API_URL
	if (typeof window !== "undefined") return window.location.origin
	return ""
}

function getAccessToken(): string | null {
	if (typeof document === "undefined") return null
	const token = document.cookie.replace(ACCESS_TOKEN_REGEXP, "$1")
	return token.length ? token : null
}

async function requestJson<TResponse>(
	path: string,
	init?: RequestInit,
): Promise<TResponse> {
	const token = getAccessToken()
	const response = await fetch(`${getBaseApiUrl()}${path}`, {
		credentials: "include",
		...init,
		headers: {
			"Content-Type": "application/json",
			...(token ? { Authorization: `Bearer ${token}` } : {}),
			...(init?.headers ?? {}),
		},
	})

	if (!response.ok) {
		const message = response.statusText || "Workflow request failed"
		throw new WorkflowApiError(response.status, message)
	}

	if (response.status === 204) {
		return null as TResponse
	}

	return (await response.json()) as TResponse
}

export function getProjectWorkspaceQueryKey(projectId: string) {
	return ["project-workspace", projectId] as const
}

export async function fetchProjectWorkspace(
	projectId: string,
): Promise<ProjectWorkspaceRead> {
	return requestJson<ProjectWorkspaceRead>(
		`/api/projects/${projectId}/workspace`,
		{ method: "GET" },
	)
}

export async function postWorkflowAction(
	projectId: string,
	action: WorkflowActionRequest,
): Promise<ProjectWorkspaceRead | null> {
	return requestJson<ProjectWorkspaceRead | null>(
		`/api/projects/${projectId}/workflow/actions`,
		{
			method: "POST",
			body: JSON.stringify(action),
		},
	)
}

export function useProjectWorkspaceQuery(projectId: string) {
	return useQuery({
		queryKey: getProjectWorkspaceQueryKey(projectId),
		queryFn: () => fetchProjectWorkspace(projectId),
		enabled: !!projectId,
	})
}

export function useWorkflowAction(projectId: string) {
	const queryClient = useQueryClient()
	const queryKey = getProjectWorkspaceQueryKey(projectId)

	return useMutation({
		mutationFn: (action: WorkflowActionRequest) =>
			postWorkflowAction(projectId, action),
		onSuccess: (workspace) => {
			if (workspace) {
				queryClient.setQueryData(queryKey, workspace)
				return
			}

			queryClient.invalidateQueries({ queryKey })
		},
		onError: (error) => {
			if (
				error instanceof WorkflowApiError &&
				error.status === 409
			) {
				queryClient.invalidateQueries({ queryKey })
			}
		},
	})
}

export function isWorkflowConflictError(error: unknown): boolean {
	return error instanceof WorkflowApiError && error.status === 409
}
