"use client"

import type { ITranscriptionEditorProps } from "./TranscriptionEditor.d"
import type { JSX } from "react"

import { useQueryClient } from "@tanstack/react-query"
import { LoaderCircle, Plus, Scissors, Trash2 } from "lucide-react"
import { FunctionComponent, useCallback, useEffect, useRef, useState } from "react"

import api from "@shared/api"
import { fetchClient } from "@shared/api"
import { useWorkspaceFiles } from "@shared/context/WorkspaceContext"
import { declOfNum } from "@shared/lib/russianNoun"
import {
	type EditorSegment,
	documentToSegments,
	segmentsToDocument,
} from "@shared/lib/transcriptionDocument"
import { SegmentSplitter } from "@features/project/SegmentSplitter"

import styles from "./TranscriptionEditor.module.scss"

/* ------------------------------------------------------------------ */
/*  Component                                                          */
/* ------------------------------------------------------------------ */

type SegmentRow = {
	id: string
	segment: EditorSegment
}

export const TranscriptionEditor: FunctionComponent<
	ITranscriptionEditorProps
> = ({ artifactId }): JSX.Element => {
	const queryClient = useQueryClient()
	const { selectedFile, setSelectedFile } = useWorkspaceFiles()
	const segmentsListRef = useRef<HTMLDivElement>(null)
	const rowIdRef = useRef(0)

	const { data: transcription, isLoading } = api.useQuery(
		"get",
		"/api/transcribe/transcriptions/by-artifact/{artifact_id}/",
		{ params: { path: { artifact_id: artifactId } } },
	)

	const [segmentRows, setSegmentRows] = useState<SegmentRow[]>([])
	const [saving, setSaving] = useState(false)
	const [dirty, setDirty] = useState(false)
	const [splittingRowId, setSplittingRowId] = useState<string | null>(null)
	const visibleStatus = saving
		? "Сохраняем изменения"
		: dirty
			? "Изменения будут сохранены автоматически"
			: null

	const createSegmentRow = useCallback(
		(segment: EditorSegment): SegmentRow => ({
			id: `segment-row-${rowIdRef.current++}`,
			segment,
		}),
		[],
	)

	useEffect(() => {
		if (transcription?.document) {
			rowIdRef.current = 0
			setSegmentRows(
				documentToSegments(transcription.document).map((segment) =>
					createSegmentRow(segment),
				),
			)
			setDirty(false)
			setSplittingRowId(null)
		}
	}, [transcription, createSegmentRow])

	// Scroll to segment when navigated from SubtitlesTrack
	useEffect(() => {
		if (!selectedFile || selectedFile.scrollToSegmentIndex == null) return
		if (segmentRows.length === 0) return

		const targetIdx = selectedFile.scrollToSegmentIndex
		const container = segmentsListRef.current
		if (!container) return

		const segmentEl = container.querySelector<HTMLElement>(
			`[data-segment-index="${targetIdx}"]`,
		)
		if (!segmentEl) return

		// Brief delay to let the DOM settle
		requestAnimationFrame(() => {
			segmentEl.scrollIntoView({ behavior: "smooth", block: "center" })
			segmentEl.classList.add(styles.highlight)
			setTimeout(() => segmentEl.classList.remove(styles.highlight), 1500)
		})

		// Clear scrollToSegmentIndex so it doesn't re-trigger
		setSelectedFile({
			id: selectedFile.id,
			path: selectedFile.path,
			source: selectedFile.source,
			artifactType: selectedFile.artifactType,
		})
	}, [selectedFile?.scrollToSegmentIndex, segmentRows.length, setSelectedFile])

	const updateSegment = useCallback(
		(rowId: string, field: keyof EditorSegment, value: string) => {
			setSegmentRows((prev) =>
				prev.map((row) => {
					if (row.id !== rowId) return row
					const updated = { ...row.segment, [field]: value }
					if (field === "text") updated.words = undefined
					return { ...row, segment: updated }
				}),
			)
			setDirty(true)
		},
		[],
	)

	const handleSplit = useCallback(
		(rowId: string, newSegments: EditorSegment[]) => {
			setSegmentRows((prev) => {
				const targetIndex = prev.findIndex((row) => row.id === rowId)
				if (targetIndex === -1) return prev
				const nextRows = newSegments.map((segment) => createSegmentRow(segment))
				return [
					...prev.slice(0, targetIndex),
					...nextRows,
					...prev.slice(targetIndex + 1),
				]
			})
			setSplittingRowId(null)
			setDirty(true)
		},
		[createSegmentRow],
	)

	const addSegment = useCallback(() => {
		setSegmentRows((prev) => {
			const lastEnd =
				prev.length > 0 ? prev[prev.length - 1].segment.endTime : "00:00.000"
			return [
				...prev,
				createSegmentRow({ startTime: lastEnd, endTime: lastEnd, text: "" }),
			]
		})
		setDirty(true)
	}, [createSegmentRow])

	const removeSegment = useCallback((rowId: string) => {
		setSegmentRows((prev) => prev.filter((row) => row.id !== rowId))
		setSplittingRowId((prev) => (prev === rowId ? null : prev))
		setDirty(true)
	}, [])

	const handleSave = useCallback(async () => {
		if (!transcription?.id) return
		setSaving(true)
		try {
			await fetchClient.PATCH(
				"/api/transcribe/transcriptions/{transcription_id}/",
				{
					params: { path: { transcription_id: transcription.id } },
					body: {
						document: segmentsToDocument(
							segmentRows.map((row) => row.segment),
						),
					},
				},
			)
			setDirty(false)
			queryClient.invalidateQueries({
				queryKey: api.queryOptions(
					"get",
					"/api/transcribe/transcriptions/by-artifact/{artifact_id}/",
					{ params: { path: { artifact_id: artifactId } } },
				).queryKey,
			})
		} finally {
			setSaving(false)
		}
	}, [transcription, segmentRows, artifactId, queryClient])

	// Auto-save when dirty (debounced)
	useEffect(() => {
		if (!dirty) return
		const timer = setTimeout(() => {
			handleSave()
		}, 1500)
		return () => clearTimeout(timer)
	}, [dirty, handleSave])

	/* Loading */
	if (isLoading) {
		return (
			<div
				className={styles.root}
				data-testid="TranscriptionEditor"
				aria-busy="true"
			>
				<div className={styles.loader} role="status" aria-live="polite">
					<LoaderCircle size={24} className={styles.spinner} />
					<span className={styles.srOnly}>Загружаем транскрипцию</span>
				</div>
			</div>
		)
	}

	/* No transcription found */
	if (!transcription) {
		return (
			<div className={styles.root} data-testid="TranscriptionEditor">
				<p className={styles.empty}>Транскрипция не найдена</p>
			</div>
		)
	}

	return (
		<div
			className={styles.root}
			data-testid="TranscriptionEditor"
			aria-busy={saving ? "true" : "false"}
		>
			<div className={styles.toolbar}>
				<div className={styles.toolbarMeta}>
					<p className={styles.toolbarTitle}>Сегменты</p>
					<div className={styles.toolbarSummary}>
						<span className={styles.segmentCount}>
							{segmentRows.length}{" "}
							{declOfNum(segmentRows.length, [
								"сегмент",
								"сегмента",
								"сегментов",
							])}
						</span>
						{visibleStatus ? (
							<p className={styles.headerStatus}>{visibleStatus}</p>
						) : null}
					</div>
				</div>
				<button className={styles.addButton} onClick={addSegment} type="button">
					<Plus size={16} />
					<span>Добавить сегмент</span>
				</button>
				<span
					className={styles.srOnly}
					role="status"
					aria-live="polite"
					aria-atomic="true"
				>
					{visibleStatus ?? ""}
				</span>
			</div>

			<div className={styles.segmentsList} ref={segmentsListRef}>
				{segmentRows.map((row, idx) => {
					const textareaId = `${row.id}-text`
					const splitDisabled = !row.segment.words || row.segment.words.length < 2

					return (
						<div
							key={row.id}
							className={styles.segment}
							data-segment-index={idx}
						>
							<div className={styles.segmentNumber} aria-hidden="true">
								{String(idx + 1).padStart(2, "0")}
							</div>
							<div className={styles.segmentMain}>
								<div className={styles.segmentMetaRow}>
									<div className={styles.timesGroup}>
										<label className={styles.timeField}>
											<span className={styles.timeLabelText}>Начало</span>
											<input
												className={styles.timeInput}
												type="text"
												value={row.segment.startTime}
												onChange={(e) =>
													updateSegment(row.id, "startTime", e.target.value)
												}
												placeholder="00:00.000"
											/>
										</label>
										<label className={styles.timeField}>
											<span className={styles.timeLabelText}>Конец</span>
											<input
												className={styles.timeInput}
												type="text"
												value={row.segment.endTime}
												onChange={(e) =>
													updateSegment(row.id, "endTime", e.target.value)
												}
												placeholder="00:00.000"
											/>
										</label>
									</div>
									<div className={styles.actionsGroup}>
										<button
											className={styles.splitButton}
											onClick={() => setSplittingRowId(row.id)}
											aria-label={
												splitDisabled
													? `Разделить сегмент ${idx + 1}: недоступно без разбивки по словам`
													: `Разделить сегмент ${idx + 1}`
											}
											title={
												splitDisabled
													? "Нет данных о словах для разделения"
													: "Разделить сегмент"
											}
											disabled={splitDisabled}
											type="button"
										>
											<Scissors size={14} />
										</button>
										<button
											className={styles.removeButton}
											onClick={() => removeSegment(row.id)}
											aria-label={`Удалить сегмент ${idx + 1}`}
											title="Удалить сегмент"
											type="button"
										>
											<Trash2 size={14} />
										</button>
									</div>
								</div>
								<label className={styles.srOnly} htmlFor={textareaId}>
									Текст сегмента {idx + 1}
								</label>
								{splittingRowId === row.id ? (
									<SegmentSplitter
										segment={row.segment}
										onSplit={(newSegs) => handleSplit(row.id, newSegs)}
										onCancel={() => setSplittingRowId(null)}
									/>
								) : (
									<textarea
										id={textareaId}
										className={styles.textArea}
										value={row.segment.text}
										onChange={(e) => updateSegment(row.id, "text", e.target.value)}
										rows={2}
										placeholder="Текст сегмента..."
									/>
								)}
							</div>
						</div>
					)
				})}
			</div>
		</div>
	)
}
