'use client';

import { TestStep, StepType, ConfigItem, ConfigType, TestCaseFile } from '@/types';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import dynamic from 'next/dynamic';
import { useState, useRef, useEffect } from 'react';
import { useI18n } from '@/i18n';
import InsertVariableDropdown from './InsertVariableDropdown';

function EditorLoading() {
    const { t } = useI18n();

    return (
        <div className="h-[180px] bg-gray-50 border border-gray-200 rounded-lg flex items-center justify-center text-gray-400 text-sm">
            {t('step.editor.loading')}
        </div>
    );
}

const PlaywrightCodeEditor = dynamic(
    () => import('./PlaywrightCodeEditor'),
    {
        ssr: false,
        loading: () => <EditorLoading />
    }
);

interface BrowserEntry {
    id: string;
    config: {
        type?: string;
        name?: string;
        url?: string;
    };
}

interface SortableStepItemProps {
    step: TestStep;
    index: number;
    browsers: BrowserEntry[];
    onRemove: () => void;
    onChange: (field: keyof TestStep, value: string) => void;
    onFilesChange?: (fileIds: string[]) => void;
    onTypeChange?: (type: StepType) => void;
    readOnly?: boolean;
    isAnyDragging?: boolean;
    projectConfigs?: ConfigItem[];
    testCaseConfigs?: ConfigItem[];
    testCaseFiles?: TestCaseFile[];
}

function isAndroidEntry(browser: BrowserEntry): boolean {
    return browser.config.type === 'android';
}

export default function SortableStepItem({ step, index, browsers, onRemove, onChange, onFilesChange, onTypeChange, readOnly, isAnyDragging, projectConfigs, testCaseConfigs, testCaseFiles }: SortableStepItemProps) {
    const { t } = useI18n();
    const stepTextareaRef = useRef<HTMLTextAreaElement>(null);
    const browserDropdownRef = useRef<HTMLDivElement>(null);
    const [codeInsertRequest, setCodeInsertRequest] = useState<{ id: string; text: string } | null>(null);
    const [browserDropdownOpen, setBrowserDropdownOpen] = useState(false);

    const {
        attributes,
        listeners,
        setNodeRef,
        transform,
        transition,
        isDragging,
    } = useSortable({ id: step.id, disabled: readOnly });

    const [validationErrors, setValidationErrors] = useState<string[]>([]);
    const stepType = step.type || 'ai-action';

    const style = {
        transform: CSS.Transform.toString(transform),
        transition,
        zIndex: isDragging ? 30 : 'auto',
        opacity: isDragging ? 0.5 : 1,
    } as React.CSSProperties;

    const hideMonacoEditor = isAnyDragging && stepType === 'playwright-code';
    const aiInsertableTypes: ConfigType[] = ['URL', 'VARIABLE', 'RANDOM_STRING'];
    const formatCodeConfigReference = (config: ConfigItem): string => {
        if (config.type === 'FILE') {
            return `testFiles[${JSON.stringify(config.name)}]`;
        }
        return `vars[${JSON.stringify(config.name)}]`;
    };

    const browserIndex = browsers.findIndex(b => b.id === step.target);
    const safeIndex = browserIndex >= 0 ? browserIndex : 0;
    const colorsLight = ['bg-blue-50', 'bg-purple-50', 'bg-orange-50', 'bg-green-50', 'bg-pink-50'];
    const colorsText = ['text-blue-700', 'text-purple-700', 'text-orange-700', 'text-green-700', 'text-pink-700'];
    const colorsBorder = ['border-blue-200', 'border-purple-200', 'border-orange-200', 'border-green-200', 'border-pink-200'];

    const colorLight = colorsLight[safeIndex % colorsLight.length];
    const colorText = colorsText[safeIndex % colorsText.length];
    const colorBorder = colorsBorder[safeIndex % colorsBorder.length];
    const selectedBrowser = browsers[safeIndex];
    const isAndroid = selectedBrowser ? isAndroidEntry(selectedBrowser) : false;
    const getDefaultBrowserLabel = (browser: BrowserEntry, indexValue: number): string => {
        if (browser.config.name) {
            return browser.config.name;
        }
        const letter = String.fromCharCode('A'.charCodeAt(0) + indexValue);
        return isAndroidEntry(browser) ? `Android ${letter}` : `Browser ${letter}`;
    };

    useEffect(() => {
        if (!browserDropdownOpen) return;
        const handleClickOutside = (event: MouseEvent) => {
            if (browserDropdownRef.current && !browserDropdownRef.current.contains(event.target as Node)) {
                setBrowserDropdownOpen(false);
            }
        };
        document.addEventListener('mousedown', handleClickOutside);
        return () => document.removeEventListener('mousedown', handleClickOutside);
    }, [browserDropdownOpen]);

    return (
        <div
            ref={setNodeRef}
            style={style}
            className="group relative p-4 bg-white rounded-xl border border-gray-200 shadow-sm hover:border-indigo-200 hover:shadow-md transition-all"
        >
            <div className="flex items-center gap-3 mb-3">
                {/* Drag Handle */}
                {!readOnly && (
                    <div
                        {...attributes}
                        {...listeners}
                        className="cursor-move p-1 text-gray-300 hover:text-gray-500 hover:bg-gray-100 rounded"
                        aria-label={t('step.drag')}
                    >
                        <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
                        </svg>
                    </div>
                )}

                <span className="flex items-center justify-center w-6 h-6 rounded-full bg-gray-100 text-xs font-mono text-gray-500 font-bold">
                    {index + 1}
                </span>

                {/* Target Select */}
                <div className="relative" ref={browserDropdownRef}>
                    <button
                        type="button"
                        onClick={() => {
                            if (readOnly) return;
                            setBrowserDropdownOpen((current) => !current);
                        }}
                        disabled={readOnly}
                        className={`text-xs font-bold uppercase tracking-wider pl-3 pr-2 py-1.5 rounded-md border min-w-[140px] flex items-center justify-between gap-2 ${readOnly ? 'cursor-not-allowed opacity-80' : 'cursor-pointer focus:ring-2 focus:ring-offset-1'} ${colorLight} ${colorText} ${colorBorder}`}
                        onPointerDown={(e) => e.stopPropagation()}
                    >
                        <span className="flex items-center gap-1.5 truncate">
                            <span className="truncate">{selectedBrowser ? getDefaultBrowserLabel(selectedBrowser, safeIndex) : step.target}</span>
                        </span>
                        <svg className={`w-3 h-3 shrink-0 ${colorText}`} fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                        </svg>
                    </button>
                    {browserDropdownOpen && !readOnly && (
                        <div className="absolute left-0 top-full mt-1 bg-white border border-gray-200 rounded-md shadow-lg z-30 py-1 min-w-[180px]">
                            {browsers.map((browser, browserListIndex) => {
                                const isSelected = browser.id === step.target;
                                return (
                                    <button
                                        key={browser.id}
                                        type="button"
                                        onClick={() => {
                                            onChange('target', browser.id);
                                            setBrowserDropdownOpen(false);
                                        }}
                                        onPointerDown={(e) => e.stopPropagation()}
                                        className={`w-full text-left px-3 py-1.5 text-xs hover:bg-gray-50 flex items-center gap-1.5 ${isSelected ? 'bg-gray-50 text-gray-900 font-medium' : 'text-gray-700'}`}
                                    >
                                        <span>{getDefaultBrowserLabel(browser, browserListIndex)}</span>
                                    </button>
                                );
                            })}
                        </div>
                    )}
                </div>

                {/* Step Type Toggle */}
                {!readOnly && onTypeChange && (
                    <div className="flex items-center gap-1 bg-gray-100 p-0.5 rounded-md ml-auto mr-2">
                        <button
                            type="button"
                            onClick={() => onTypeChange('ai-action')}
                            onPointerDown={(e) => e.stopPropagation()}
                            className={`px-2 py-1 text-xs font-medium rounded transition-all ${stepType === 'ai-action'
                                ? 'bg-white text-indigo-600 shadow-sm'
                                : 'text-gray-500 hover:text-gray-700'
                                }`}
                            title={t('step.type.aiTitle')}
                        >
                            AI
                        </button>
                        <button
                            type="button"
                            onClick={() => !isAndroid && onTypeChange('playwright-code')}
                            onPointerDown={(e) => e.stopPropagation()}
                            disabled={isAndroid}
                            className={`px-2 py-1 text-xs font-medium rounded transition-all ${stepType === 'playwright-code'
                                ? 'bg-white text-orange-600 shadow-sm'
                                : isAndroid
                                    ? 'text-gray-300 cursor-not-allowed'
                                    : 'text-gray-500 hover:text-gray-700'
                                }`}
                            title={isAndroid ? 'Playwright Code is not available for Android targets' : t('step.type.codeTitle')}
                        >
                            Code
                        </button>
                    </div>
                )}

                {!readOnly && (
                    <button
                        type="button"
                        onClick={onRemove}
                        className={`${onTypeChange ? '' : 'ml-auto'} text-gray-300 hover:text-red-500 p-1 rounded-full hover:bg-red-50 transition-colors`}
                        aria-label={t('step.remove')}
                    >
                        <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                        </svg>
                    </button>
                )}
            </div>

            <div className="space-y-1">
                <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider">
                    {stepType === 'ai-action' ? t('step.label.ai') : t('step.label.code')}
                </label>

                {stepType === 'ai-action' ? (
                    <div className="space-y-3">
                        <textarea
                            ref={stepTextareaRef}
                            value={step.action}
                            onChange={(e) => {
                                onChange('action', e.target.value);
                                e.target.style.height = 'auto';
                                e.target.style.height = e.target.scrollHeight + 'px';
                            }}
                            onPointerDown={(e) => e.stopPropagation()}
                            onKeyDown={(e) => e.stopPropagation()}
                            placeholder={t('step.ai.placeholder')}
                            className="w-full text-sm border-gray-200 rounded-lg focus:ring-indigo-500 focus:border-indigo-500 min-h-[80px] py-3 px-3 resize-none bg-gray-50 focus:bg-white transition-colors disabled:bg-gray-100 disabled:text-gray-600"
                            required
                            rows={3}
                            disabled={readOnly}
                        />
                        {!readOnly && ((projectConfigs && projectConfigs.length > 0) || (testCaseConfigs && testCaseConfigs.length > 0)) && (
                            <InsertVariableDropdown
                                projectConfigs={projectConfigs || []}
                                testCaseConfigs={testCaseConfigs || []}
                                allowedTypes={aiInsertableTypes}
                                onInsert={(ref) => {
                                    const textarea = stepTextareaRef.current;
                                    if (!textarea) {
                                        onChange('action', step.action + ref);
                                        return;
                                    }
                                    const start = textarea.selectionStart;
                                    const end = textarea.selectionEnd;
                                    const newValue = step.action.substring(0, start) + ref + step.action.substring(end);
                                    onChange('action', newValue);
                                    requestAnimationFrame(() => {
                                        textarea.focus();
                                        const cursorPos = start + ref.length;
                                        textarea.setSelectionRange(cursorPos, cursorPos);
                                    });
                                }}
                            />
                        )}
                    </div>
                ) : hideMonacoEditor ? (
                    <div className="h-[180px] bg-gray-50 border border-gray-200 rounded-lg flex items-center justify-center text-gray-400 text-sm">
                        <code className="text-xs text-gray-500 truncate max-w-full px-4">{step.action || t('step.label.code')}</code>
                    </div>
                ) : (
                    <div onPointerDown={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()}>
                        <PlaywrightCodeEditor
                            value={step.action}
                            onChange={(value) => onChange('action', value)}
                            readOnly={readOnly}
                            onValidationChange={(isValid, errors) => setValidationErrors(errors)}
                            insertRequest={codeInsertRequest}
                            onInsertHandled={(requestId) => {
                                setCodeInsertRequest((current) => {
                                    if (!current || current.id !== requestId) {
                                        return current;
                                    }
                                    return null;
                                });
                            }}
                        />
                        {!readOnly && (
                            ((projectConfigs && projectConfigs.length > 0)
                                || (testCaseConfigs && testCaseConfigs.length > 0)
                                || (testCaseFiles && testCaseFiles.length > 0))
                        ) && (
                            <div className="mt-2">
                                <InsertVariableDropdown
                                    projectConfigs={projectConfigs || []}
                                    testCaseConfigs={testCaseConfigs || []}
                                    formatRef={formatCodeConfigReference}
                                    testFiles={testCaseFiles}
                                    formatTestFileRef={(file) => `files[${JSON.stringify(file.id)}]`}
                                    onInsertTestFile={(file) => {
                                        if (!onFilesChange) {
                                            return;
                                        }
                                        const currentFileIds = step.files || [];
                                        if (currentFileIds.includes(file.id)) {
                                            return;
                                        }
                                        onFilesChange([...currentFileIds, file.id]);
                                    }}
                                    onInsert={(ref) => {
                                        setCodeInsertRequest({
                                            id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
                                            text: ref,
                                        });
                                    }}
                                />
                            </div>
                        )}
                        {validationErrors.length > 0 && (
                            <div className="text-xs text-red-500 mt-1 flex items-center gap-1">
                                <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
                                </svg>
                                {validationErrors[0]}
                            </div>
                        )}
                    </div>
                )}
            </div>
        </div >
    );
}

export type { BrowserEntry, SortableStepItemProps };
