import React, { useEffect, useState } from 'react';
import { serialService } from '../services/serialService';
import { BMSConfig } from '../types';
import * as JBD from '../services/jbdProtocol';
import { Save, RefreshCw, AlertTriangle, CheckCircle, RotateCw } from 'lucide-react';

const Settings: React.FC = () => {
  // 초기 상태를 빈 객체로 시작하여 UI는 렌더링되되 값은 비어있도록 함
  const [config, setConfig] = useState<Partial<BMSConfig>>({});
  const [busyReg, setBusyReg] = useState<number | null>(null); // 현재 작업 중인 레지스터 (로딩 표시용)
  const [globalLoading, setGlobalLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [successMsg, setSuccessMsg] = useState<string | null>(null);

  // 전체 읽기
  const readAllSettings = async () => {
    setGlobalLoading(true);
    setError(null);
    setSuccessMsg(null);
    try {
      await serialService.enterFactoryModeRead();

      // Helper with delay
      const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

      const p = async (reg: number) => {
        const val = await serialService.readRegister(reg);
        await delay(250);
        return val;
      };

      const pBytes = async (reg: number) => {
        const val = await serialService.readRegisterBytes(reg);
        await delay(250);
        return val;
      };

      // 병렬 처리는 시리얼 통신에서 꼬일 수 있으므로 순차 처리 권장 (await 사용)
      // 주요 레지스터 읽기
      const newConfig: Partial<BMSConfig> = {};

      newConfig.cellOvp = await p(JBD.REG_COVP);
      newConfig.cellOvpRel = await p(JBD.REG_COVP_REL);
      newConfig.cellUvp = await p(JBD.REG_CUVP);
      newConfig.cellUvpRel = await p(JBD.REG_CUVP_REL);
      newConfig.packOvp = await p(JBD.REG_POVP);
      newConfig.packOvpRel = await p(JBD.REG_POVP_REL);
      newConfig.packUvp = await p(JBD.REG_PUVP);
      newConfig.packUvpRel = await p(JBD.REG_PUVP_REL);

      newConfig.chgOt = await p(JBD.REG_CHG_OT);
      newConfig.chgOtRel = await p(JBD.REG_CHG_OT_REL);
      newConfig.chgUt = await p(JBD.REG_CHG_UT);
      newConfig.chgUtRel = await p(JBD.REG_CHG_UT_REL);
      newConfig.dsgOt = await p(JBD.REG_DSG_OT);
      newConfig.dsgOtRel = await p(JBD.REG_DSG_OT_REL);
      newConfig.dsgUt = await p(JBD.REG_DSG_UT);
      newConfig.dsgUtRel = await p(JBD.REG_DSG_UT_REL);

      newConfig.covpHigh = await p(JBD.REG_COVP_HIGH);
      newConfig.cuvpHigh = await p(JBD.REG_CUVP_HIGH);
      newConfig.funcConfig = await p(JBD.REG_FUNC_CONFIG);
      newConfig.ntcConfig = await p(JBD.REG_NTC_CONFIG);

      newConfig.balStart = await p(JBD.REG_BAL_START);
      newConfig.balWindow = await p(JBD.REG_BAL_WINDOW);

      newConfig.designCapacity = await p(JBD.REG_DESIGN_CAP);
      newConfig.cycleCapacity = await p(JBD.REG_CYCLE_CAP);
      newConfig.dsgRate = await p(JBD.REG_DSG_RATE);
      newConfig.cap100 = await p(JBD.REG_CAP_100);
      newConfig.cap80 = await p(JBD.REG_CAP_80);
      newConfig.cap60 = await p(JBD.REG_CAP_60);
      newConfig.cap40 = await p(JBD.REG_CAP_40);
      newConfig.cap20 = await p(JBD.REG_CAP_20);
      newConfig.cap0 = await p(JBD.REG_CAP_0);
      newConfig.fetCtrl = await p(JBD.REG_FET_CTRL);
      newConfig.ledTimer = await p(JBD.REG_LED_TIMER);

      newConfig.shuntRes = await p(JBD.REG_SHUNT_RES);
      newConfig.cellCnt = await p(JBD.REG_CELL_CNT);
      newConfig.cycleCnt = await p(JBD.REG_CYCLE_CNT);
      newConfig.serialNum = await p(JBD.REG_SERIAL_NUM);

      newConfig.mfgDate = await p(JBD.REG_MFG_DATE);

      const mfgNameRaw = await pBytes(JBD.REG_MFG_NAME);
      const deviceNameRaw = await pBytes(JBD.REG_DEVICE_NAME);
      const barcodeRaw = await pBytes(JBD.REG_BARCODE);

      newConfig.mfgName = JBD.JBDProtocol.parseString(mfgNameRaw);
      newConfig.deviceName = JBD.JBDProtocol.parseString(deviceNameRaw);
      newConfig.barcode = JBD.JBDProtocol.parseString(barcodeRaw);

      await serialService.exitFactoryMode();

      setConfig(prev => ({ ...prev, ...newConfig }));
      setSuccessMsg("모든 설정을 불러왔습니다.");
    } catch (e: any) {
      setError("설정 읽기 실패: " + e.message);
    } finally {
      setGlobalLoading(false);
    }
  };

  // 개별 항목 읽기
  const handleReadSingle = async (reg: number, field: keyof BMSConfig, type: 'int' | 'string' | 'bytes' | 'date' = 'int') => {
    setBusyReg(reg);
    setError(null);
    setSuccessMsg(null);
    try {
      await serialService.enterFactoryModeRead();

      let val: any;
      if (type === 'int' || type === 'date') { // date reads as int raw
        val = await serialService.readRegister(reg);
      } else if (type === 'string' || type === 'bytes') {
        const bytes = await serialService.readRegisterBytes(reg);
        if (type === 'string') {
          val = JBD.JBDProtocol.parseString(bytes);
        } else {
          val = bytes; // bytes not fully supported in single row yet unless custom
        }
      }

      await serialService.exitFactoryMode();

      setConfig(prev => ({ ...prev, [field]: val }));
      setSuccessMsg("항목을 불러왔습니다.");
    } catch (e: any) {
      setError("읽기 실패: " + e.message);
    } finally {
      setBusyReg(null);
    }
  };

  // 개별 항목 저장
  const handleSaveSingle = async (reg: number, value: number | string | Uint8Array, type: 'int' | 'string' | 'bytes' | 'date' = 'int') => {
    setBusyReg(reg);
    setError(null);
    setSuccessMsg(null);
    try {
      await serialService.enterFactoryModeWrite();

      if (type === 'int' || type === 'date') {
        await serialService.writeRegister(reg, value as number);
      } else if (type === 'string') {
        const bytes = JBD.JBDProtocol.encodeString(value as string);
        await serialService.writeRegisterBytes(reg, bytes);
      } else if (type === 'bytes') {
        await serialService.writeRegisterBytes(reg, value as Uint8Array);
      }

      await serialService.exitFactoryMode();
      setSuccessMsg("설정이 저장되었습니다.");
      setTimeout(() => setSuccessMsg(null), 2000);
    } catch (e: any) {
      setError("저장 실패: " + e.message);
    } finally {
      setBusyReg(null);
    }
  };

  // 그룹 컴포넌트
  const Group: React.FC<{ title: string, children: React.ReactNode }> = ({ title, children }) => (
    <div className="bg-gray-900 rounded-xl border border-gray-800 shadow-xl overflow-hidden mb-6">
      <div className="bg-gray-800/50 px-5 py-3 border-b border-gray-700">
        <h3 className="text-lg font-bold text-gray-200 flex items-center gap-2">
          {title}
        </h3>
      </div>
      <div className="p-1 space-y-1">{children}</div>
    </div>
  );

  // 개별 설정 행 컴포넌트
  const SettingRow: React.FC<{
    label: string;
    val: number | string | undefined;
    unit?: string;
    reg: number;
    field: keyof BMSConfig;
    scale?: number;
    type?: 'int' | 'string' | 'bytes' | 'date';
  }> = ({ label, val, unit, reg, field, scale = 1, type = 'int' }) => {
    const [localVal, setLocalVal] = useState<string | number>('');
    const [isDirty, setIsDirty] = useState(false);
    const isBusy = busyReg === reg;

    // config 값이 업데이트되면 로컬 상태 동기화
    useEffect(() => {
      if (val === undefined || val === null) {
        setLocalVal('');
        setIsDirty(false);
      } else {
        if (type === 'date') {
          setLocalVal(JBD.JBDProtocol.parseDate(val as number));
        } else if (type === 'int') {
          setLocalVal(Number(val) * scale);
        } else {
          setLocalVal(val as string);
        }
        setIsDirty(false);
      }
    }, [val, scale, type]);

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
      setLocalVal(e.target.value);
      setIsDirty(true);
    };

    const onRead = () => {
      handleReadSingle(reg, field, type as 'int' | 'string' | 'bytes' | 'date');
    };

    const onSave = () => {
      let payload: any = localVal;
      if (type === 'int') {
        payload = Number(localVal) / scale;
      } else if (type === 'date') {
        payload = JBD.JBDProtocol.encodeDate(localVal as string);
      }

      handleSaveSingle(reg, payload, type as 'int' | 'string' | 'bytes' | 'date');
      setIsDirty(false);
    };

    return (
      <div className="flex items-center justify-between p-3 bg-gray-950/50 border-b border-gray-800 last:border-0 hover:bg-gray-900 transition-colors">
        <div className="flex-1 pr-4">
          <div className="text-sm text-gray-300 font-medium">{label}</div>
          <div className="text-xs text-gray-600 font-mono">ADDR: 0x{reg.toString(16).toUpperCase().padStart(2, '0')}</div>
        </div>

        <div className="flex items-center gap-2">
          <div className="relative">
            <input
              type={type === 'date' ? 'date' : 'text'}
              value={localVal}
              onChange={handleChange}
              placeholder={val === undefined ? "?" : ""}
              disabled={isBusy || globalLoading}
              className={`bg-gray-900 border ${isDirty ? 'border-yellow-600' : 'border-gray-700'} text-gray-100 text-right px-3 py-1.5 rounded focus:outline-none focus:border-blue-500 font-mono h-9 ${type === 'string' ? 'w-40' : 'w-28'}`}
            />
            {unit && <span className="absolute right-2 top-2 text-gray-500 text-xs pointer-events-none opacity-50">{type !== 'date' ? unit : ''}</span>}
          </div>

          <button
            onClick={onRead}
            disabled={isBusy || globalLoading}
            title="개별 읽기"
            className="p-2 bg-gray-800 text-gray-400 hover:text-blue-400 hover:bg-gray-700 rounded-lg transition-all disabled:opacity-50"
          >
            <RotateCw size={16} className={isBusy ? 'animate-spin text-blue-500' : ''} />
          </button>

          <button
            onClick={onSave}
            disabled={isBusy || globalLoading}
            title="개별 저장"
            className={`p-2 rounded-lg transition-all disabled:opacity-50 ${isDirty ? 'bg-blue-600 text-white hover:bg-blue-500' : 'bg-gray-800 text-gray-500 hover:text-gray-300'}`}
          >
            <Save size={16} />
          </button>
        </div>
      </div>
    );
  };

  return (
    <div className="p-6 pb-24 overflow-y-auto h-full max-w-6xl mx-auto">
      {/* 상단 툴바 */}
      <div className="flex flex-col md:flex-row justify-between items-center mb-6 gap-4 sticky top-0 bg-gray-950/90 backdrop-blur z-20 py-4 border-b border-gray-800">
        <div>
          <h2 className="text-2xl font-bold text-gray-200">EEPROM 설정</h2>
          <p className="text-gray-400 text-sm">BMS 내부 파라미터를 개별적으로 읽거나 수정할 수 있습니다.</p>
        </div>
        <div className="flex gap-2">
          <button
            onClick={readAllSettings}
            disabled={globalLoading}
            className="flex items-center px-5 py-2.5 bg-blue-600 hover:bg-blue-500 text-white rounded-xl transition-colors shadow-lg shadow-blue-900/20 text-sm font-bold"
          >
            <RefreshCw size={18} className={`mr-2 ${globalLoading ? 'animate-spin' : ''}`} />
            전체 설정 읽기
          </button>
        </div>
      </div>

      {/* 메시지 영역 */}
      <div className="space-y-2 mb-6">
        {error && (
          <div className="p-4 bg-red-900/20 border border-red-900/50 rounded-xl text-red-400 flex items-center animate-in slide-in-from-top-2">
            <AlertTriangle size={20} className="mr-3" />
            {error}
          </div>
        )}
        {successMsg && (
          <div className="p-4 bg-green-900/20 border border-green-900/50 rounded-xl text-green-400 flex items-center animate-in slide-in-from-top-2">
            <CheckCircle size={20} className="mr-3" />
            {successMsg}
          </div>
        )}
      </div>

      {/* 설정 그리드 */}
      <div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
        <div className="space-y-6">
          <Group title="전압 보호 (Voltage Protection)">
            <SettingRow label="셀 과전압 (Cell OVP)" unit="mV" val={config.cellOvp} reg={JBD.REG_COVP} field="cellOvp" />
            <SettingRow label="셀 과전압 해제 (Release)" unit="mV" val={config.cellOvpRel} reg={JBD.REG_COVP_REL} field="cellOvpRel" />
            <SettingRow label="셀 저전압 (Cell UVP)" unit="mV" val={config.cellUvp} reg={JBD.REG_CUVP} field="cellUvp" />
            <SettingRow label="셀 저전압 해제 (Release)" unit="mV" val={config.cellUvpRel} reg={JBD.REG_CUVP_REL} field="cellUvpRel" />
            <SettingRow label="팩 과전압 (Pack OVP)" unit="V" val={config.packOvp} reg={JBD.REG_POVP} field="packOvp" scale={0.01} />
            <SettingRow label="팩 과전압 해제 (Release)" unit="V" val={config.packOvpRel} reg={JBD.REG_POVP_REL} field="packOvpRel" scale={0.01} />
            <SettingRow label="팩 저전압 (Pack UVP)" unit="V" val={config.packUvp} reg={JBD.REG_PUVP} field="packUvp" scale={0.01} />
            <SettingRow label="팩 저전압 해제 (Release)" unit="V" val={config.packUvpRel} reg={JBD.REG_PUVP_REL} field="packUvpRel" scale={0.01} />
          </Group>

          <Group title="온도 보호 (Temperature)">
            <SettingRow label="충전 과온 (Chg OT)" unit="°C" val={config.chgOt} reg={JBD.REG_CHG_OT} field="chgOt" type="int" />
            <SettingRow label="충전 과온 해제 (Release)" unit="°C" val={config.chgOtRel} reg={JBD.REG_CHG_OT_REL} field="chgOtRel" />
            <SettingRow label="충전 저온 (Chg UT)" unit="°C" val={config.chgUt} reg={JBD.REG_CHG_UT} field="chgUt" />
            <SettingRow label="충전 저온 해제 (Release)" unit="°C" val={config.chgUtRel} reg={JBD.REG_CHG_UT_REL} field="chgUtRel" />
            <SettingRow label="방전 과온 (Dsg OT)" unit="°C" val={config.dsgOt} reg={JBD.REG_DSG_OT} field="dsgOt" />
            <SettingRow label="방전 과온 해제 (Release)" unit="°C" val={config.dsgOtRel} reg={JBD.REG_DSG_OT_REL} field="dsgOtRel" />
          </Group>

          <Group title="하드웨어 정보 (Hardware Info)">
            <SettingRow label="제조일자 (Mfg Date)" unit="" val={config.mfgDate} reg={JBD.REG_MFG_DATE} field="mfgDate" type="date" />
            <SettingRow label="제조사명 (Mfg Name)" unit="" val={config.mfgName} reg={JBD.REG_MFG_NAME} field="mfgName" type="string" />
            <SettingRow label="장치명 (Device Name)" unit="" val={config.deviceName} reg={JBD.REG_DEVICE_NAME} field="deviceName" type="string" />
            <SettingRow label="바코드 (Barcode)" unit="" val={config.barcode} reg={JBD.REG_BARCODE} field="barcode" type="string" />
            <SettingRow label="션트 저항 (Shunt)" unit="mΩ" val={config.shuntRes} reg={JBD.REG_SHUNT_RES} field="shuntRes" scale={0.1} />
            <SettingRow label="셀 개수 (Cell Count)" unit="S" val={config.cellCnt} reg={JBD.REG_CELL_CNT} field="cellCnt" />
          </Group>
        </div>

        <div className="space-y-6">
          <Group title="용량 설정 (Capacity Settings)">
            <SettingRow label="설계 용량 (Design Cap)" unit="Ah" val={config.designCapacity} reg={JBD.REG_DESIGN_CAP} field="designCapacity" scale={0.01} />
            <SettingRow label="사이클 용량 (Cycle Cap)" unit="Ah" val={config.cycleCapacity} reg={JBD.REG_CYCLE_CAP} field="cycleCapacity" scale={0.01} />
            <SettingRow label="방전율 (Dsg Rate)" unit="%" val={config.dsgRate} reg={JBD.REG_DSG_RATE} field="dsgRate" scale={0.1} />
            <SettingRow label="100% 전압 (Vol at 100%)" unit="mV" val={config.cap100} reg={JBD.REG_CAP_100} field="cap100" />
            <SettingRow label="80% 전압 (Vol at 80%)" unit="mV" val={config.cap80} reg={JBD.REG_CAP_80} field="cap80" />
            <SettingRow label="60% 전압 (Vol at 60%)" unit="mV" val={config.cap60} reg={JBD.REG_CAP_60} field="cap60" />
            <SettingRow label="40% 전압 (Vol at 40%)" unit="mV" val={config.cap40} reg={JBD.REG_CAP_40} field="cap40" />
            <SettingRow label="20% 전압 (Vol at 20%)" unit="mV" val={config.cap20} reg={JBD.REG_CAP_20} field="cap20" />
            <SettingRow label="0% 전압 (Vol at 0%)" unit="mV" val={config.cap0} reg={JBD.REG_CAP_0} field="cap0" />
          </Group>

          <Group title="밸런스 설정 (Balancer)">
            <SettingRow label="시작 전압 (Start Volt)" unit="mV" val={config.balStart} reg={JBD.REG_BAL_START} field="balStart" />
            <SettingRow label="정밀도 (Precision)" unit="mV" val={config.balWindow} reg={JBD.REG_BAL_WINDOW} field="balWindow" />
          </Group>

          <Group title="기타 설정 (Misc)">
            <SettingRow label="기능 설정 (Func Config)" unit="HEX" val={config.funcConfig} reg={JBD.REG_FUNC_CONFIG} field="funcConfig" />
            <SettingRow label="NTC 설정 (NTC Config)" unit="HEX" val={config.ntcConfig} reg={JBD.REG_NTC_CONFIG} field="ntcConfig" />
            <SettingRow label="FET 제어 시간" unit="s" val={config.fetCtrl} reg={JBD.REG_FET_CTRL} field="fetCtrl" />
            <SettingRow label="LED 타이머" unit="s" val={config.ledTimer} reg={JBD.REG_LED_TIMER} field="ledTimer" />
          </Group>
        </div>
      </div>
    </div>
  );
};

export default Settings;