import { useState, useRef, useEffect } from 'react';
import { Recorder } from '../../lib/recorder';
import VoiceCards from './VoiceCards';
import './ChatterboxTTS.css';

const API_URL = 'https://back.hack.kinsle.ru/process-audio';

interface ChatterboxTTSProps {
	onComplete?: () => void;
}

const ChatterboxTTS = ({ onComplete }: ChatterboxTTSProps) => {
	// Recording state
	const [isRecording, setIsRecording] = useState(false);
	const [hasRecording, setHasRecording] = useState(false);
	const [isUsingRecordedVoice, setIsUsingRecordedVoice] = useState(false);
	const [recordStatus, setRecordStatus] = useState('Нажмите для записи');
	const [recordTime, setRecordTime] = useState('');
	const [showVoiceText, setShowVoiceText] = useState(false);
	const [showVoicePreview, setShowVoicePreview] = useState(false);
	const [recordedAudioUrl, setRecordedAudioUrl] = useState('');

	// File state
	const [fileName, setFileName] = useState('');
	const [isDragOver, setIsDragOver] = useState(false);
	const [voiceBlob, setVoiceBlob] = useState<Blob | null>(null);

	// Form state
	const [text, setText] = useState('В прошлом месяце мы достигли нового рубежа.');
	const [language, setLanguage] = useState('ru');
	const [exaggeration, setExaggeration] = useState(0.5);
	const [temperature, setTemperature] = useState(0.8);
	const [cfgWeight, setCfgWeight] = useState(0.5);
	const [seed, setSeed] = useState(0);

	// UI state
	const [loading, setLoading] = useState(false);
	const [error, setError] = useState('');
	const [resultUrl, setResultUrl] = useState('');

	// Refs (не тригерят ре-рендер)
	const recorderRef = useRef<Recorder | null>(null);
	const audioContextRef = useRef<AudioContext | null>(null);
	const streamRef = useRef<MediaStream | null>(null);
	const recordedBlobRef = useRef<Blob | null>(null);
	const recordingStartRef = useRef<number>(0);
	const timerIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
	const fileInputRef = useRef<HTMLInputElement>(null);
	const fileRef = useRef<File | null>(null);

	// Запрос микрофона при монтировании
	useEffect(() => {
		navigator.mediaDevices.getUserMedia({ audio: true })
			.then(stream => stream.getTracks().forEach(t => t.stop()))
			.catch(() => { });
	}, []);

	const updateTimer = () => {
		const elapsed = Math.floor((Date.now() - recordingStartRef.current) / 1000);
		const mins = Math.floor(elapsed / 60).toString().padStart(2, '0');
		const secs = (elapsed % 60).toString().padStart(2, '0');
		setRecordTime(`${mins}:${secs}`);
	};

	const startRecording = async () => {
		try {
			const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
			streamRef.current = stream;

			const audioContext = new AudioContext();
			audioContextRef.current = audioContext;

			const source = audioContext.createMediaStreamSource(stream);
			const recorder = await Recorder.create(source, { numChannels: 1 });
			recorderRef.current = recorder;

			setIsRecording(true);
			setHasRecording(false);
			setShowVoiceText(true);
			setShowVoicePreview(false);
			setIsUsingRecordedVoice(false);
			setRecordStatus('Идёт запись...');
			setRecordTime('00:00');

			recordingStartRef.current = Date.now();
			updateTimer();
			timerIntervalRef.current = setInterval(updateTimer, 1000);
		} catch (err) {
			alert('Не удалось получить доступ к микрофону: ' + (err as Error).message);
		}
	};

	const stopRecording = () => {
		const recorder = recorderRef.current;
		if (!recorder) return;

		recorder.stop();

		// Сразу обновляем UI — не ждём окончания экспорта
		setIsRecording(false);
		setRecordStatus('Обработка...');
		if (timerIntervalRef.current) {
			clearInterval(timerIntervalRef.current);
			timerIntervalRef.current = null;
		}
		setRecordTime('');

		recorder.exportWAV((blob) => {
			recorder.clear();
			recorder.destroy();
			recorderRef.current = null;

			streamRef.current?.getTracks().forEach(t => t.stop());
			streamRef.current = null;
			audioContextRef.current?.close();
			audioContextRef.current = null;

			recordedBlobRef.current = blob;
			setRecordedAudioUrl(URL.createObjectURL(blob));
			setShowVoicePreview(true);
			setShowVoiceText(false);
			setRecordStatus('Запись завершена');
			setHasRecording(true);
		});
	};

	const handleRecordClick = () => {
		if (isRecording) stopRecording();
		else startRecording();
	};

	const handleRetry = () => {
		setShowVoicePreview(false);
		setHasRecording(false);
		setIsUsingRecordedVoice(false);
		setRecordStatus('Нажмите для записи');
		recordedBlobRef.current = null;
		setVoiceBlob(null);
	};

	const handleUseRecording = () => {
		setIsUsingRecordedVoice(true);
		setRecordStatus('✅ Голосовое сообщение сохранено');
		setVoiceBlob(recordedBlobRef.current);
		// Сбрасываем файл
		fileRef.current = null;
		setFileName('');
		if (fileInputRef.current) fileInputRef.current.value = '';
	};

	const updateFileName = (file: File) => {
		fileRef.current = file;
		setFileName(file.name);
		setVoiceBlob(file);
		setIsUsingRecordedVoice(false);
	};

	const handleDrop = (e: React.DragEvent) => {
		e.preventDefault();
		setIsDragOver(false);
		const file = e.dataTransfer.files[0];
		if (file) updateFileName(file);
	};

	const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
		const file = e.target.files?.[0];
		if (file) updateFileName(file);
	};

	const handleSubmit = async (e: React.FormEvent) => {
		e.preventDefault();

		setResultUrl('');
		setError('');
		setLoading(true);

		try {
			const formData = new FormData();

			if (isUsingRecordedVoice) {
				if (!recordedBlobRef.current) {
					throw new Error('Запись голоса потеряна — запишите снова');
				}
				formData.append('audio_file', recordedBlobRef.current, 'voice_recording.wav');
			} else if (fileRef.current) {
				formData.append('audio_file', fileRef.current);
			} else {
				throw new Error('Выберите аудио файл или запишите голос');
			}

			formData.append('text', text);
			formData.append('language_id', language);
			formData.append('exaggeration', String(exaggeration));
			formData.append('temperature', String(temperature));
			formData.append('seed_num', String(seed));
			formData.append('cfg_weight', String(cfgWeight));

			console.log('[ChatterboxTTS] отправка:', {
				audio: isUsingRecordedVoice ? 'recorded blob' : fileRef.current?.name,
				text, language, exaggeration, temperature, cfgWeight, seed,
			});

			const response = await fetch(API_URL, { method: 'POST', body: formData });

			const contentType = response.headers.get('Content-Type') ?? '';
			console.log('[ChatterboxTTS] ответ:', response.status, contentType);

			if (!response.ok || contentType.includes('application/json')) {
				const errData = await response.json().catch(() => ({}));
				const msg = (errData as { error?: string }).error;
				if (msg) throw new Error(msg);
				if (!response.ok) throw new Error(`HTTP ${response.status}`);
				throw new Error('Сервер вернул JSON вместо аудио — возможно audio_file не принят');
			}

			const blob = await response.blob();
			setResultUrl(URL.createObjectURL(blob));
		} catch (err) {
			setError('❌ Ошибка: ' + (err as Error).message);
		} finally {
			setLoading(false);
		}
	};

	const voiceSectionClass = [
		'voice-section',
		isRecording ? 'recording' : '',
		hasRecording && !isRecording ? 'has-recording' : '',
	].filter(Boolean).join(' ');

	return (
		<div className="chatterbox-container">
			<h1>Подделка голоса</h1>

			<p>
				Deepfake — синтез правдоподобных поддельных изображений, видео и звука при помощи искусственного интеллекта. Чаще всего дипфейки изображают известных людей в вымышленных ситуациях.
			</p>

			<p>
				Давайте на нашем примере разберемся с этим! Для этого нам нужен небольшой отрывок вашего голоса. Не переживайте - это безопасно! Мы трепетно относимся к чувствительной информации, не храним ваши данные после обработки и не передаем их третьим лицам - все строго в соответствии с политикой соглашения.
			</p>

			<form onSubmit={handleSubmit}>
				{/* Запись голоса */}
				<div className={voiceSectionClass}>
					<div className="voice-label">
						🎤 Запишите голосовое сообщение - достаточно 10-15 секунд вашего голоса
						{isUsingRecordedVoice && <span className="check-badge">✓ Готово</span>}
					</div>

					<button type="button" className={`record-btn${isRecording ? ' recording' : ''}`} onClick={handleRecordClick}>
						{isRecording ? '⏹' : '⏺'}
					</button>

					<div className="record-status">{recordStatus}</div>
					{recordTime && <div className="record-timer">{recordTime}</div>}

					{showVoiceText && (
						<div className="voice-text">
							📢 Произнесите, например: <span style={{ color: '#00FFFF' }}>"Хакатон 2026 походим модуль deepfake, кейс Цент Инвест команда Атейкин"</span>
						</div>
					)}

					{showVoicePreview && (
						<div className="voice-preview">
							<audio src={recordedAudioUrl} controls />
							<div className="voice-actions">
								<button type="button" className="btn-retry" onClick={handleRetry}>🔄 Перезаписать</button>
								<button type="button" className="btn-use" onClick={handleUseRecording}>✅ Использовать</button>
							</div>
						</div>
					)}
				</div>

				{/* Загрузка файла */}
				<div className="or-divider">или загрузите файл фрагмента голоса, желательно свой :D</div>

				<div className="form-group">
					<div
						className={`file-input-wrapper${fileName ? ' has-file' : ''}`}
						onClick={() => fileInputRef.current?.click()}
						onDragOver={(e) => { e.preventDefault(); setIsDragOver(true); }}
						onDragLeave={() => setIsDragOver(false)}
						onDrop={handleDrop}
						style={isDragOver ? { borderColor: '#00FFFF' } : undefined}
					>
						<input ref={fileInputRef} type="file" accept="audio/*" onChange={handleFileChange} style={{ display: 'none' }} />
						<div>{fileName ? '✅ Файл выбран' : '📁 Кликни или перетащи аудио файл'}</div>
						{fileName && <div className="file-name">{fileName}</div>}
					</div>
				</div>

				<p>
					Дипфейки часто создают и применяют в преступных целях. Их могут использовать для распространения ложных новостей, обмана или прохождения аудио- и видео- аутентификации.
				</p>

				<p>
					Имея небольшой отрывок речи человека, мошенники могут полностью возсоздать интонацию, произношение и темперамет голоса.
				</p>


				{voiceBlob && (
					<div>
						<p>
							Вот примеры дипфейков.
						</p>

						<VoiceCards voiceBlob={voiceBlob} />

						<h2>
							Вы можете попробовать самостоятельно сделат дипфейк из своего голоса!
						</h2>

						{/* Текст */}
						<div className="form-group">
							<label>Текст для синтеза (макс 300 символов)</label>
							<textarea maxLength={300} value={text} onChange={e => setText(e.target.value)} placeholder="Введите текст..." />
							<div className="char-counter"><span>{text.length}</span>/300</div>
						</div>

						{/* Язык */}
						{/* <div className="form-group">
			<label>Язык</label>
			<select value={language} onChange={e => setLanguage(e.target.value)}>
				<option value="en">English</option>
				<option value="ru">Russian</option>
				<option value="de">German</option>
				<option value="es">Spanish</option>
				<option value="fr">French</option>
				<option value="it">Italian</option>
				<option value="pt">Portuguese</option>
				<option value="hi">Hindi</option>
			</select>
			</div> */}

						{/* Слайдеры */}
						<div className="form-group">
							<label>Exaggeration (экспрессивность)</label>
							<div className="slider-group">
								<input type="range" min="0.25" max="2" step="0.05" value={exaggeration} onChange={e => setExaggeration(Number(e.target.value))} />
								<span className="slider-value">{exaggeration}</span>
							</div>
						</div>

						<div className="form-group">
							<label>Temperature (разнообразие)</label>
							<div className="slider-group">
								<input type="range" min="0.05" max="5" step="0.05" value={temperature} onChange={e => setTemperature(Number(e.target.value))} />
								<span className="slider-value">{temperature}</span>
							</div>
						</div>

						<div className="form-group">
							<label>CFG Weight</label>
							<div className="slider-group">
								<input type="range" min="0.2" max="1" step="0.05" value={cfgWeight} onChange={e => setCfgWeight(Number(e.target.value))} />
								<span className="slider-value">{cfgWeight}</span>
							</div>
						</div>

						<div className="two-col">
							<div className="form-group">
								<label>Random Seed (0 = random)</label>
								<input type="number" value={seed} min={0} onChange={e => setSeed(Number(e.target.value))} />
							</div>
						</div>

						<button type="submit" className="submit-btn" disabled={loading}>
							🚀 Сгенерировать аудио
						</button>
					</div>
				)}
			</form>

			{loading && (
				<div className="loading-block">
					<div className="spinner" />
					<p>Генерируем аудио... Это может занять 5-15 секунд</p>
				</div>
			)}

			{error && <div className="error-block">{error}</div>}

			{resultUrl && (
				<div className="result-block">
					<h3>✅ Готово!</h3>
					<audio src={resultUrl} controls />
					<br />
					<a href={resultUrl} className="download-btn" download="output.wav">💾 Скачать WAV'ку!</a>
					{onComplete && (
						<button className="complete-btn" onClick={onComplete}>
							✓ Завершить кейс
						</button>
					)}
				</div>
			)}
		</div>
	);
};

export default ChatterboxTTS;
