import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import { Button, Space, message } from 'antd';
import { PlayCircleOutlined, ClearOutlined } from '@ant-design/icons';
import { useStore } from '../store';
import { buildRpcConnectionConfig } from '../utils/connectionRpcConfig';
import { t, type I18nParams } from '../i18n';
import { useOptionalI18n } from '../i18n/provider';
import Editor, { type OnMount } from './MonacoEditor';
import {
    isMacLikePlatform,
    normalizeBlurForPlatform,
    normalizeOpacityForPlatform,
    resolveAppearanceValues,
} from '../utils/appearance';
import { buildRedisWorkbenchTheme } from './redisViewerWorkbenchTheme';

interface RedisCommandEditorProps {
    connectionId: string;
    redisDB: number;
}

interface CommandResult {
    command: string;
    result: any;
    error?: string;
    timestamp: number;
    durationMs: number;
}

export const REDIS_COMMAND_EDITOR_MIN_HEIGHT = 120;
export const REDIS_COMMAND_OUTPUT_MIN_HEIGHT = 240;
export const REDIS_COMMAND_RESIZER_HEIGHT = 8;

export const clampRedisCommandEditorHeight = (
    requestedHeight: number,
    containerHeight: number | undefined,
): number => {
    const minHeight = REDIS_COMMAND_EDITOR_MIN_HEIGHT;
    const fallbackMaxHeight = 800;
    const maxHeight = containerHeight
        ? Math.max(
            minHeight,
            containerHeight - REDIS_COMMAND_OUTPUT_MIN_HEIGHT - REDIS_COMMAND_RESIZER_HEIGHT,
        )
        : fallbackMaxHeight;

    return Math.min(Math.max(requestedHeight, minHeight), maxHeight);
};

// 智能解析 Redis 脚本块，保护多行引号内的换行符
function parseRedisScriptBlocks(script: string): string[] {
    const blocks: string[] = [];
    let currentBlock = "";
    let inQuote: string | null = null;
    let isEscaping = false;

    const lines = script.split('\n');

    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        const trimmed = line.trim();

        if (!inQuote && (trimmed === '' || trimmed.startsWith('//') || trimmed.startsWith('#'))) {
            continue;
        }

        for (let j = 0; j < line.length; j++) {
            const char = line[j];
            
            if (isEscaping) {
                isEscaping = false;
                currentBlock += char;
                continue;
            }

            if (char === '\\') {
                isEscaping = true;
                currentBlock += char;
                continue;
            }

            if (char === '"' || char === "'") {
                if (inQuote === char) {
                    inQuote = null;
                } else if (!inQuote) {
                    inQuote = char;
                }
            }

            currentBlock += char;
        }

        if (inQuote || (i < lines.length - 1 && currentBlock.trim() !== '')) {
            if (!inQuote) {
                blocks.push(currentBlock.trim());
                currentBlock = "";
            } else {
                currentBlock += '\n';
            }
        }
    }

    if (currentBlock.trim() !== '') {
        blocks.push(currentBlock.trim());
    }

    return blocks.filter(b => b.trim() !== '');
}

const RedisCommandEditor: React.FC<RedisCommandEditorProps> = ({ connectionId, redisDB }) => {
    const connections = useStore(state => state.connections);
    const theme = useStore(state => state.theme);
    const appearance = useStore(state => state.appearance);
    const i18n = useOptionalI18n();
    const i18nLanguage = i18n?.language;
    const tr = (key: string, params?: I18nParams) => t(key, params, i18nLanguage);
    const connection = connections.find(c => c.id === connectionId);
    const darkMode = theme === 'dark';
    const isV2Ui = appearance.uiVersion === 'v2';
    const resolvedAppearance = resolveAppearanceValues(appearance);
    const opacity = normalizeOpacityForPlatform(resolvedAppearance.opacity);
    const blur = normalizeBlurForPlatform(resolvedAppearance.blur);
    const disableLocalBackdropFilter = isMacLikePlatform();
    const workbenchTheme = useMemo(
        () => buildRedisWorkbenchTheme({ darkMode, opacity, blur, disableBackdropFilter: disableLocalBackdropFilter }),
        [blur, darkMode, disableLocalBackdropFilter, opacity, appearance.uiVersion],
    );

    const [command, setCommand] = useState('');
    const [results, setResults] = useState<CommandResult[]>([]);
    const [loading, setLoading] = useState(false);
    
    // UI Layout state
    const [editorHeight, setEditorHeight] = useState(250);
    const dragRef = useRef<{ startY: number; startHeight: number } | null>(null);
    const containerRef = useRef<HTMLDivElement>(null);
    const resultsEndRef = useRef<HTMLDivElement>(null);
    
    const editorRef = useRef<any>(null);

    const getConfig = useCallback(() => {
        if (!connection) return null;
        return {
            ...connection.config,
            port: Number(connection.config.port),
            password: connection.config.password || "",
            useSSH: connection.config.useSSH || false,
            ssh: connection.config.ssh || { host: "", port: 22, user: "", password: "", keyPath: "" },
            redisDB: redisDB
        };
    }, [connection, redisDB]);

    const handleEditorMount: OnMount = (editor, monaco) => {
        editorRef.current = editor;
        editor.addCommand(
            monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
            () => handleExecute()
        );

        if (!(window as any).__redisCompletionRegistered) {
            (window as any).__redisCompletionRegistered = true;
            
            const redisCommands = [
                "APPEND", "AUTH", "BGREWRITEAOF", "BGSAVE", "BITCOUNT", "BITFIELD", "BITOP", 
                "BITPOS", "BLPOP", "BRPOP", "BRPOPLPUSH", "BZMPOP", "BZPOPMIN", "BZPOPMAX",
                "CLIENT", "CLUSTER", "COMMAND", "CONFIG", "DBSIZE", "DEBUG", "DECR", "DECRBY",
                "DEL", "DISCARD", "DUMP", "ECHO", "EVAL", "EVALSHA", "EXEC", "EXISTS", "EXPIRE",
                "EXPIREAT", "EXPIRETIME", "FLUSHALL", "FLUSHDB", "GEOADD", "GEODIST", "GEOHASH",
                "GEOPOS", "GEORADIUS", "GEORADIUSBYMEMBER", "GEOSEARCH", "GEOSEARCHSTORE",
                "GET", "GETBIT", "GETDEL", "GETEX", "GETRANGE", "GETSET", "HDEL", "HELLO", 
                "HEXISTS", "HGET", "HGETALL", "HINCRBY", "HINCRBYFLOAT", "HKEYS", "HLEN", 
                "HMGET", "HMSET", "HSCAN", "HSET", "HSETNX", "HSTRLEN", "HVALS", "INCR", 
                "INCRBY", "INCRBYFLOAT", "INFO", "KEYS", "LASTSAVE", "LCS", "LINDEX", "LINSERT",
                "LLEN", "LMOVE", "LMPOP", "LPOP", "LPOS", "LPUSH", "LPUSHX", "LRANGE", "LREM",
                "LSET", "LTRIM", "MEMORY", "MGET", "MIGRATE", "MODULE", "MONITOR", "MOVE", "MSET",
                "MSETNX", "MULTI", "OBJECT", "PERSIST", "PEXPIRE", "PEXPIREAT", "PEXPIRETIME",
                "PFADD", "PFCOUNT", "PFMERGE", "PING", "PSETEX", "PSUBSCRIBE", "PTTL", "PUBLISH",
                "PUBSUB", "PUNSUBSCRIBE", "QUIT", "RANDOMKEY", "READONLY", "READWRITE", "RENAME",
                "RENAMENX", "RESET", "RESTORE", "ROLE", "RPOP", "RPOPLPUSH", "RPUSH", "RPUSHX",
                "SADD", "SAVE", "SCAN", "SCARD", "SCRIPT", "SDIFF", "SDIFFSTORE", "SELECT",
                "SET", "SETBIT", "SETEX", "SETNX", "SETRANGE", "SHUTDOWN", "SINTER", "SINTERCARD",
                "SINTERSTORE", "SISMEMBER", "SLAVEOF", "SLOWLOG", "SMEMBERS", "SMISMEMBER",
                "SMOVE", "SORT", "SORT_RO", "SPOP", "SRANDMEMBER", "SREM", "SSCAN", "STRLEN",
                "SUBSCRIBE", "SUNION", "SUNIONSTORE", "SWAPDB", "SYNC", "TIME", "TOUCH", "TTL",
                "TYPE", "UNLINK", "UNSUBSCRIBE", "UNWATCH", "WAIT", "WATCH", "XACK", "XADD",
                "XAUTOCLAIM", "XCLAIM", "XDEL", "XGROUP", "XINFO", "XLEN", "XPENDING", "XRANGE",
                "XREAD", "XREADGROUP", "XREVRANGE", "XTRIM", "ZADD", "ZCARD", "ZCOUNT", "ZDIFF",
                "ZDIFFSTORE", "ZINCRBY", "ZINTER", "ZINTERCARD", "ZINTERSTORE", "ZLEXCOUNT",
                "ZMPOP", "ZMSCORE", "ZPOPMAX", "ZPOPMIN", "ZRANDMEMBER", "ZRANGE", "ZRANGEBYLEX",
                "ZRANGEBYSCORE", "ZRANK", "ZREM", "ZREMRANGEBYLEX", "ZREMRANGEBYRANK",
                "ZREMRANGEBYSCORE", "ZREVRANGE", "ZREVRANGEBYLEX", "ZREVRANGEBYSCORE", "ZREVRANK",
                "ZSCAN", "ZSCORE", "ZUNION", "ZUNIONSTORE"
            ];
            
            monaco.languages.registerCompletionItemProvider('redis', {
                provideCompletionItems: (model: any, position: any) => {
                    const word = model.getWordUntilPosition(position);
                    const range = {
                        startLineNumber: position.lineNumber,
                        endLineNumber: position.lineNumber,
                        startColumn: word.startColumn,
                        endColumn: word.endColumn
                    };
                    return {
                        suggestions: redisCommands.map(cmd => ({
                            label: cmd,
                            kind: monaco.languages.CompletionItemKind.Keyword,
                            insertText: cmd,
                            range: range,
                            detail: tr('redis_command.completion.detail')
                        }))
                    };
                }
            });
        }
    };

    const handleExecute = async () => {
        const config = getConfig();
        if (!config) return;

        let cmdToExecute = '';
        
        // 1. 获取用户是否有高亮选中的文本
        const selection = editorRef.current?.getSelection();
        if (selection && !selection.isEmpty()) {
            cmdToExecute = editorRef.current?.getModel()?.getValueInRange(selection) || '';
        } else {
            // 没有选中则取全部文本
            cmdToExecute = editorRef.current?.getValue() || '';
        }

        cmdToExecute = cmdToExecute.trim();
        if (!cmdToExecute) {
            message.warning(tr('redis_command.message.command_required'));
            return;
        }

        // 2. 智能解析多行命令
        const commands = parseRedisScriptBlocks(cmdToExecute);
        if (commands.length === 0) return;

        setLoading(true);
        const newResults: CommandResult[] = [];

        for (const cmd of commands) {
            const start = Date.now();
            try {
                const res = await (window as any).go.app.App.RedisExecuteCommand(buildRpcConnectionConfig(config), cmd);
                newResults.push({
                    command: cmd,
                    result: res.success ? res.data : null,
                    error: res.success ? undefined : res.message,
                    timestamp: Date.now(),
                    durationMs: Date.now() - start
                });
            } catch (e: any) {
                newResults.push({
                    command: cmd,
                    result: null,
                    error: e?.message || String(e),
                    timestamp: Date.now(),
                    durationMs: Date.now() - start
                });
            }
        }

        setResults(prev => [...prev, ...newResults]);
        setLoading(false);
    };
    
    // Auto scroll to bottom when new results arrive
    useEffect(() => {
        if (resultsEndRef.current) {
            resultsEndRef.current.scrollIntoView({ behavior: 'smooth' });
        }
    }, [results]);

    const handleClear = () => {
        setResults([]);
    };

    const formatResult = (result: any): React.ReactNode => {
        if (result === null || result === undefined) {
            return <span style={{ color: '#569cd6' }}>(nil)</span>;
        }
        if (typeof result === 'string') {
            // 尝试美化 JSON 字符串
            try {
                const parsed = JSON.parse(result);
                if (typeof parsed === 'object' && parsed !== null) {
                    return (
                        <div style={{ marginTop: 4, padding: 8, background: 'rgba(0,0,0,0.2)', borderRadius: 4 }}>
                            {JSON.stringify(parsed, null, 2)}
                        </div>
                    );
                }
            } catch (e) {
                // not a valid json, just return string
            }
            return <span style={{ color: '#ce9178' }}>"{result}"</span>;
        }
        if (typeof result === 'number') {
            return <span style={{ color: '#b5cea8' }}>(integer) {result}</span>;
        }
        if (Array.isArray(result)) {
            if (result.length === 0) {
                return '(empty array)';
            }
            return (
                <div style={{ marginLeft: 8 }}>
                    {result.map((item, index) => (
                        <div key={index} style={{ display: 'flex' }}>
                            <span style={{ color: '#608b4e', marginRight: 8, userSelect: 'none' }}>{index + 1})</span>
                            <div>{formatResult(item)}</div>
                        </div>
                    ))}
                </div>
            );
        }
        if (typeof result === 'object') {
            return JSON.stringify(result, null, 2);
        }
        return String(result);
    };

    // Resizing logic
    const handleDragStart = (e: React.MouseEvent) => {
        e.preventDefault();
        dragRef.current = { startY: e.clientY, startHeight: editorHeight };
        document.addEventListener('mousemove', handleDragMove);
        document.addEventListener('mouseup', handleDragEnd);
        document.body.style.cursor = 'row-resize';
    };

    const handleDragMove = useCallback((e: MouseEvent) => {
        if (!dragRef.current) return;
        const delta = e.clientY - dragRef.current.startY;
        let newHeight = dragRef.current.startHeight + delta;
        
        // 限制输入区高度，避免拖拽后压缩掉底部输出区。
        newHeight = clampRedisCommandEditorHeight(
            newHeight,
            containerRef.current?.clientHeight,
        );
        
        setEditorHeight(newHeight);
        
        // 更新编辑器布局
        if (editorRef.current) {
            editorRef.current.layout();
        }
    }, []);

    const handleDragEnd = useCallback(() => {
        dragRef.current = null;
        document.removeEventListener('mousemove', handleDragMove);
        document.removeEventListener('mouseup', handleDragEnd);
        document.body.style.cursor = 'default';
        if (editorRef.current) {
            editorRef.current.layout();
        }
    }, [handleDragMove]);

    if (!connection) {
        return <div style={{ padding: 20 }}>{tr('redis_command.state.connection_not_found')}</div>;
    }

    return (
        <div
            ref={containerRef}
            data-redis-command-editor="true"
            style={{
                display: 'flex',
                flexDirection: 'column',
                height: '100%',
                overflow: 'hidden',
                background: workbenchTheme.appBg,
                color: workbenchTheme.textPrimary,
                backdropFilter: workbenchTheme.backdropFilter,
                WebkitBackdropFilter: workbenchTheme.backdropFilter,
            }}
        >
            {/* Editor Top Pane */}
            <div
                data-redis-command-input-pane="true"
                style={{
                    height: editorHeight,
                    minHeight: REDIS_COMMAND_EDITOR_MIN_HEIGHT,
                    display: 'flex',
                    flexDirection: 'column',
                    background: workbenchTheme.panelBg,
                    borderBottom: workbenchTheme.panelBorder,
                }}
            >
                <div style={{ padding: '8px 12px', borderBottom: workbenchTheme.panelBorder, display: 'flex', justifyContent: 'space-between', alignItems: 'center', background: workbenchTheme.panelBgStrong }}>
                    <Space>
                        <span style={{ fontWeight: 600, color: workbenchTheme.textPrimary }}>{tr('redis_command.title.console')}</span>
                        <span style={{ color: workbenchTheme.textSecondary, fontSize: 13, background: workbenchTheme.statusTagMutedBg, border: workbenchTheme.statusTagMutedBorder, padding: '2px 8px', borderRadius: 12 }}>db{redisDB}</span>
                    </Space>
                    <Space>
                        <Button
                            type="primary"
                            icon={<PlayCircleOutlined />}
                            onClick={handleExecute}
                            loading={loading}
                        >
                            {tr('redis_command.action.execute')}
                        </Button>
                    </Space>
                </div>
                <div style={{ flex: 1, minHeight: 0, position: 'relative' }}>
                    <Editor
                        theme={darkMode ? 'transparent-dark' : 'transparent-light'}
                        gonaviTypography="code"
                        defaultLanguage="redis"
                        language="redis"
                        value={command}
                        onChange={(value) => setCommand(value || '')}
                        onMount={handleEditorMount}
                        options={{
                            minimap: { enabled: false },
                            lineNumbers: 'on',
                            wordWrap: 'on',
                            scrollBeyondLastLine: false,
                            automaticLayout: true,
                            tabSize: 4,
                            padding: { top: 10, bottom: 10 }
                        }}
                    />
                </div>
            </div>

            {/* Resizer Handle */}
            <div 
                className="horizontal-resizer"
                data-redis-command-resizer="true"
                onMouseDown={handleDragStart}
                style={{ 
                    height: REDIS_COMMAND_RESIZER_HEIGHT,
                    cursor: 'row-resize', 
                    background: workbenchTheme.panelBgStrong,
                    borderTop: workbenchTheme.panelBorder,
                    borderBottom: workbenchTheme.panelBorder,
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                    zIndex: 10
                }}
            >
                <div style={{ width: 40, height: 4, background: workbenchTheme.textMuted, borderRadius: 2, opacity: 0.6 }} />
            </div>

            {/* Results Terminal Bottom Pane */}
            <div
                data-redis-command-output-pane="true"
                style={{
                    flex: 1,
                    minHeight: REDIS_COMMAND_OUTPUT_MIN_HEIGHT,
                    display: 'flex',
                    flexDirection: 'column',
                    overflow: 'hidden',
                    background: darkMode ? '#111418' : workbenchTheme.panelBg,
                }}
            >
                 <div style={{ padding: '4px 12px', background: darkMode ? '#1b1f27' : workbenchTheme.panelBgStrong, display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderBottom: workbenchTheme.panelBorder }}>
                    <span style={{ color: workbenchTheme.textSecondary, fontSize: 12 }}>{tr('redis_command.output.title')}</span>
                    <Button type="text" size="small" icon={<ClearOutlined />} onClick={handleClear} style={{ color: workbenchTheme.textSecondary }}>{tr('redis_command.action.clear_console')}</Button>
                </div>
                <div
                    data-redis-command-output-terminal="true"
                    style={{
                        flex: 1,
                        minHeight: 0,
                        overflow: 'auto',
                        background: darkMode ? '#111418' : '#f8fafc',
                        color: darkMode ? '#d4d4d4' : '#0f172a',
                        fontFamily: 'var(--gn-font-mono)',
                        fontSize: 'var(--gn-font-size-mono, 13px)',
                        lineHeight: '1.62',
                        padding: 12,
                    }}
                >
                    {results.length === 0 ? (
                        <div style={{ color: workbenchTheme.textMuted, textAlign: 'center', marginTop: 40 }}>
                            <div>{tr('redis_command.output.empty_hint')}</div>
                            <div style={{ fontSize: 12, marginTop: 12 }}>
                                {tr('redis_command.output.selection_tip')}
                            </div>
                        </div>
                    ) : (
                        results.map((item, index) => (
                            <div key={item.timestamp + index} style={{ marginBottom: 16 }}>
                                <div style={{ color: '#569cd6', marginBottom: 6, fontWeight: 'bold' }}>
                                    <span style={{ color: '#4CAF50', marginRight: 8 }}>➜</span>
                                    {item.command}
                                    <span style={{ color: workbenchTheme.textMuted, fontSize: 11, marginLeft: 12, fontWeight: 'normal' }}>[{item.durationMs}ms]</span>
                                </div>
                                
                                <div style={{ paddingLeft: 20 }}>
                                    {item.error ? (
                                        <div style={{ color: '#f14c4c', whiteSpace: 'pre-wrap' }}>
                                            (error) {item.error}
                                        </div>
                                    ) : (
                                        <div style={{ whiteSpace: 'pre-wrap' }}>
                                            {formatResult(item.result)}
                                        </div>
                                    )}
                                </div>
                            </div>
                        ))
                    )}
                    <div ref={resultsEndRef} />
                </div>
            </div>
        </div>
    );
};

export default RedisCommandEditor;
