
import React, { useState, useRef, useEffect } from 'react';
import { serialService } from '../services/serialService';
import { Terminal as TerminalIcon, Send, Trash2, ArrowUp, ArrowDown } from 'lucide-react';

interface LogEntry {
  id: number;
  type: 'tx' | 'rx' | 'info' | 'error';
  timestamp: string;
  data: string;
}

const Terminal: React.FC = () => {
  const [logs, setLogs] = useState<LogEntry[]>([]);
  const [input, setInput] = useState('');
  const [autoScroll, setAutoScroll] = useState(true);
  const logsContainerRef = useRef<HTMLDivElement>(null);

  const MAX_LOGS = 200;

  useEffect(() => {
    // Subscribe to serial service logs
    serialService.setLogCallback((type, data) => {
      setLogs(prev => {
        const newLog: LogEntry = {
          id: Date.now() + Math.random(), // Ensure unique key for fast updates
          type,
          timestamp: new Date().toLocaleTimeString([], { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" }),
          data
        };
        // NEWEST FIRST: Prepend new log to the beginning of the array
        const newLogs = [newLog, ...prev];

        if (newLogs.length > MAX_LOGS) {
          return newLogs.slice(0, MAX_LOGS);
        }
        return newLogs;
      });
    });

    return () => {
      serialService.setLogCallback(null);
    };
  }, []);

  useEffect(() => {
    // If auto-scroll is on, force scroll to top when logs change
    if (autoScroll && logsContainerRef.current) {
      logsContainerRef.current.scrollTop = 0;
    }
  }, [logs, autoScroll]);

  const handleSend = async () => {
    if (!input.trim()) return;

    // Remove spaces and validate hex
    const hexStr = input.replace(/\s+/g, '');
    if (!/^[0-9A-Fa-f]+$/.test(hexStr) || hexStr.length % 2 !== 0) {
      // Local error log (prepended)
      setLogs(prev => [{
        id: Date.now(),
        type: 'error',
        timestamp: new Date().toLocaleTimeString(),
        data: '유효하지 않은 HEX 포맷입니다.'
      }, ...prev]);
      return;
    }

    const bytes = new Uint8Array(hexStr.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16)));

    try {
      await serialService.sendRaw(bytes);
      // readRaw also triggers callback inside service
      await serialService.readRaw();
    } catch (e: any) {
      // Errors from service are logged via callback usually
    }
    setInput('');
  };

  return (
    <div className="flex flex-col h-full bg-gray-50">
      <div className="flex justify-between items-center p-3 border-b border-gray-200 bg-white">
        <div className="flex items-center gap-2 overflow-hidden">
          <TerminalIcon size={18} className="text-gray-500 shrink-0" />
          <span className="font-semibold text-gray-700 truncate">Terminal / Logs</span>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={() => setAutoScroll(!autoScroll)}
            className={`p-1.5 rounded transition-colors ${autoScroll ? 'text-green-600 bg-green-100' : 'text-gray-400 hover:text-gray-600'}`}
            title={autoScroll ? "Auto-scroll: ON (Top)" : "Auto-scroll: OFF"}
          >
            {/* Icon indicates scroll direction focus */}
            <ArrowUp size={16} className={autoScroll ? "" : "opacity-50"} />
          </button>
          <button onClick={() => setLogs([])} className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-100 rounded transition-colors" title="Clear Logs">
            <Trash2 size={16} />
          </button>
        </div>
      </div>

      <div className="flex-1 bg-white overflow-hidden flex flex-col font-mono text-xs shadow-inner">
        {/* Input Area (Top) or Bottom? Keeping input at bottom is standard, logs flow down from top */}

        <div
          ref={logsContainerRef}
          className="flex-1 overflow-y-auto p-2 space-y-1 scroll-smooth"
        >
          {logs.length === 0 && <div className="text-gray-500 text-center mt-4 italic">대기 중... (Logs)</div>}

          {logs.map(log => (
            <div key={log.id} className="flex gap-2 animate-in fade-in slide-in-from-top-1 hover:bg-gray-100 p-0.5 rounded border-b border-gray-100 last:border-0">
              <span className="text-gray-500 shrink-0 select-none">[{log.timestamp}]</span>
              <div className="break-all flex-1">
                {log.type === 'tx' && <span className="text-blue-600 font-bold mr-1">TX</span>}
                {log.type === 'rx' && <span className="text-green-600 font-bold mr-1">RX</span>}
                {log.type === 'error' && <span className="text-red-500 font-bold mr-1">ERR</span>}
                {log.type === 'info' && <span className="text-gray-500 font-bold mr-1">INF</span>}
                <span className={`${log.type === 'error' ? 'text-red-600' : 'text-gray-800'}`}>
                  {log.data}
                </span>
              </div>
            </div>
          ))}
        </div>

        <div className="p-2 border-t border-gray-200 bg-gray-50">
          <div className="flex gap-2">
            <input
              type="text"
              value={input}
              onChange={(e) => setInput(e.target.value)}
              onKeyDown={(e) => e.key === 'Enter' && handleSend()}
              placeholder="HEX (e.g. DD A5 03...)"
              className="flex-1 bg-white border border-gray-300 rounded px-2 py-1.5 text-gray-900 focus:outline-none focus:border-blue-500 font-mono text-xs"
            />
            <button
              onClick={handleSend}
              className="bg-blue-600 hover:bg-blue-500 text-white px-3 py-1.5 rounded flex items-center gap-1 transition-colors text-xs font-bold"
            >
              <Send size={14} />
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Terminal;
