import React, {useState, useEffect, useRef} from 'react';
import {
  StyleSheet,
  View,
  Text,
  TouchableOpacity,
  FlatList,
  ScrollView,
  Platform,
  PermissionsAndroid,
  DeviceEventEmitter,
  NativeEventEmitter,
  NativeModules,
  Alert,
} from 'react-native';
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';

// ── Native module types ──────────────────────────────────────────────

const DEVICE_TYPE_KEYS = [
  'AM3S', 'AM4', 'PO3', 'BP5', 'BP5S', 'BP3L', 'BP7', 'BP7S',
  'KN550', 'HS2', 'HS2S', 'HS4S', 'BG1', 'BG1S', 'BG5', 'BG5S',
  'ECG3', 'BTM', 'TS28B', 'NT13B',
] as const;

type DeviceTypeName = (typeof DEVICE_TYPE_KEYS)[number];
type DiscoveryConstant = string | number;

interface IHealthDeviceManager {
  AM3S: DiscoveryConstant; AM4: DiscoveryConstant; PO3: DiscoveryConstant;
  BP5: DiscoveryConstant; BP5S: DiscoveryConstant; BP3L: DiscoveryConstant;
  BP7: DiscoveryConstant; BP7S: DiscoveryConstant; KN550: DiscoveryConstant;
  HS2: DiscoveryConstant; HS2S: DiscoveryConstant; HS4S: DiscoveryConstant;
  BG1: DiscoveryConstant; BG1S: DiscoveryConstant; BG5: DiscoveryConstant;
  BG5S: DiscoveryConstant; ECG3: DiscoveryConstant; BTM: DiscoveryConstant;
  TS28B: DiscoveryConstant; NT13B: DiscoveryConstant;
  Event_Scan_Device: string;
  Event_Scan_Finish: string;
  Event_Device_Connected: string;
  Event_Device_Connect_Failed: string;
  Event_Device_Disconnect: string;
  Event_Authenticate_Result: string;
  startDiscovery(type: DeviceTypeName | string): void;
  stopDiscovery(): void;
  connectDevice(mac: string, type: string): void;
  disconnectDevice(mac: string, type: string): void;
  sdkAuthWithLicense(license: string): void;
  authenConfigureInfo(userName: string, clientID: string, clientSecret: string): void;
  getDevicesIDPS(mac: string, callback: (idps: Record<string, string>) => void): void;
}

interface IBP550BTModule {
  Event_Notify: string;
  getBattery(mac: string): void;
  getOffLineNum(mac: string): void;
  getOffLineData(mac: string): void;
  getFunctionInfo(mac: string): void;
  disconnect(mac: string): void;
  getAllConnectedDevices(): void;
}

const iHealthDeviceManagerModule =
  NativeModules.iHealthDeviceManagerModule as IHealthDeviceManager;
const BP550BTModule =
  NativeModules.BP550BTModule as IBP550BTModule;

type Device = {
  mac: string;
  type: string;
  rssi?: number;
  timestamp: number;
};

// ── Helpers ──────────────────────────────────────────────────────────

async function requestAndroidPermissions(): Promise<boolean> {
  if (Platform.OS !== 'android') return true;
  const permissions: string[] = [];
  if (Platform.Version >= 31) {
    permissions.push(
      PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
      PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
    );
  }
  permissions.push(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
  const results = await PermissionsAndroid.requestMultiple(permissions as any);
  return Object.values(results).every(
    r => r === PermissionsAndroid.RESULTS.GRANTED,
  );
}

function getEmitter() {
  return Platform.OS === 'ios'
    ? new NativeEventEmitter(NativeModules.iHealthDeviceManagerModule)
    : DeviceEventEmitter;
}

function getBPEmitter() {
  return Platform.OS === 'ios'
    ? new NativeEventEmitter(NativeModules.BP550BTModule)
    : DeviceEventEmitter;
}

// ── Device Detail Screen ─────────────────────────────────────────────

function DeviceScreen({
  device,
  onBack,
}: {
  device: Device;
  onBack: () => void;
}) {
  const [connected, setConnected] = useState(false);
  const [connecting, setConnecting] = useState(false);
  const [log, setLog] = useState<string[]>([]);

  const addLog = (msg: string) =>
    setLog(prev => [`[${new Date().toLocaleTimeString()}] ${msg}`, ...prev]);

  useEffect(() => {
    const emitter = getEmitter();

    const connSub = emitter.addListener(
      iHealthDeviceManagerModule.Event_Device_Connected ?? 'event_device_connected',
      (e: {mac: string; type: string}) => {
        if (e.mac === device.mac) {
          setConnected(true);
          setConnecting(false);
          addLog(`Connected to ${e.type}`);
        }
      },
    );

    const failSub = emitter.addListener(
      iHealthDeviceManagerModule.Event_Device_Connect_Failed ?? 'event_device_connect_failed',
      (e: {mac: string; errorid?: number}) => {
        if (e.mac === device.mac) {
          setConnecting(false);
          addLog(`Connection failed (error: ${e.errorid ?? 'unknown'})`);
        }
      },
    );

    const dcSub = emitter.addListener(
      iHealthDeviceManagerModule.Event_Device_Disconnect ?? 'event_device_disconnect',
      (e: {mac: string}) => {
        if (e.mac === device.mac) {
          setConnected(false);
          addLog('Disconnected');
        }
      },
    );

    // BP550BT event listener
    const bpEmitter = getBPEmitter();
    const notifySub = bpEmitter.addListener(
      BP550BTModule?.Event_Notify ?? 'event_notify',
      (e: Record<string, unknown>) => {
        addLog(JSON.stringify(e, null, 2));
      },
    );

    return () => {
      connSub.remove();
      failSub.remove();
      dcSub.remove();
      notifySub.remove();
    };
  }, [device.mac]);

  const connect = () => {
    setConnecting(true);
    addLog(`Connecting to ${device.mac}...`);
    iHealthDeviceManagerModule.connectDevice(device.mac, device.type);
  };

  const disconnect = () => {
    addLog('Disconnecting...');
    if (BP550BTModule) {
      BP550BTModule.disconnect(device.mac);
    } else {
      iHealthDeviceManagerModule.disconnectDevice(device.mac, device.type);
    }
  };

  const actions: {label: string; fn: () => void; needsConnect: boolean}[] = [
    {
      label: 'Get Battery',
      needsConnect: true,
      fn: () => {
        addLog('Requesting battery...');
        BP550BTModule.getBattery(device.mac);
      },
    },
    {
      label: 'Get Function Info',
      needsConnect: true,
      fn: () => {
        addLog('Requesting function info...');
        BP550BTModule.getFunctionInfo(device.mac);
      },
    },
    {
      label: 'Get Offline Count',
      needsConnect: true,
      fn: () => {
        addLog('Requesting offline data count...');
        BP550BTModule.getOffLineNum(device.mac);
      },
    },
    {
      label: 'Get Offline Data',
      needsConnect: true,
      fn: () => {
        addLog('Requesting offline data...');
        BP550BTModule.getOffLineData(device.mac);
      },
    },
    {
      label: 'Get IDPS',
      needsConnect: false,
      fn: () => {
        addLog('Requesting IDPS...');
        iHealthDeviceManagerModule.getDevicesIDPS(device.mac, (idps) => {
          addLog(`IDPS: ${JSON.stringify(idps, null, 2)}`);
        });
      },
    },
  ];

  return (
    <SafeAreaView style={styles.container}>
      <TouchableOpacity style={styles.backButton} onPress={onBack}>
        <Text style={styles.backText}>Back</Text>
      </TouchableOpacity>

      <Text style={styles.title}>{device.type}</Text>
      <Text style={styles.deviceMac}>{device.mac}</Text>
      <Text style={[styles.statusBadge, connected && styles.statusConnected]}>
        {connecting ? 'Connecting...' : connected ? 'Connected' : 'Disconnected'}
      </Text>

      {!connected && !connecting && (
        <TouchableOpacity style={styles.button} onPress={connect}>
          <Text style={styles.buttonText}>Connect</Text>
        </TouchableOpacity>
      )}
      {connected && (
        <TouchableOpacity
          style={[styles.button, styles.buttonStop]}
          onPress={disconnect}>
          <Text style={styles.buttonText}>Disconnect</Text>
        </TouchableOpacity>
      )}

      <Text style={styles.sectionTitle}>Actions</Text>
      <ScrollView
        horizontal
        showsHorizontalScrollIndicator={false}
        style={styles.actionsRow}>
        {actions.map(a => (
          <TouchableOpacity
            key={a.label}
            style={[
              styles.actionButton,
              a.needsConnect && !connected && styles.actionDisabled,
            ]}
            disabled={a.needsConnect && !connected}
            onPress={a.fn}>
            <Text
              style={[
                styles.actionText,
                a.needsConnect && !connected && styles.actionTextDisabled,
              ]}>
              {a.label}
            </Text>
          </TouchableOpacity>
        ))}
      </ScrollView>

      <Text style={styles.sectionTitle}>Log</Text>
      <FlatList
        data={log}
        keyExtractor={(_, i) => String(i)}
        renderItem={({item}) => <Text style={styles.logLine}>{item}</Text>}
        style={styles.logList}
      />
    </SafeAreaView>
  );
}

// ── Scanner Screen ───────────────────────────────────────────────────

function ScannerScreen({onSelectDevice}: {onSelectDevice: (d: Device) => void}) {
  const [devices, setDevices] = useState<Device[]>([]);
  const [scanning, setScanning] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const devicesRef = useRef<Device[]>([]);

  useEffect(() => {
    if (!iHealthDeviceManagerModule) {
      setError('iHealth native module not found.');
      return;
    }
    const emitter = getEmitter();

    const scanSub = emitter.addListener(
      iHealthDeviceManagerModule.Event_Scan_Device ?? 'event_scan_device',
      (event: {mac: string; type: string; rssi?: number}) => {
        const {mac = '', type = 'Unknown', rssi} = event;
        if (type === 'AM3') return;

        const existing = devicesRef.current.findIndex(d => d.mac === mac);
        let updated: Device[];
        if (existing >= 0) {
          updated = [...devicesRef.current];
          updated[existing] = {mac, type, rssi, timestamp: Date.now()};
        } else {
          updated = [
            ...devicesRef.current,
            {mac, type, rssi, timestamp: Date.now()},
          ];
        }
        devicesRef.current = updated;
        setDevices(updated);
      },
    );

    const finishSub = emitter.addListener(
      iHealthDeviceManagerModule.Event_Scan_Finish ?? 'event_scan_finish',
      () => setScanning(false),
    );

    return () => {
      scanSub.remove();
      finishSub.remove();
    };
  }, []);

  const startScan = async () => {
    setError(null);
    const granted = await requestAndroidPermissions();
    if (!granted) {
      setError('Bluetooth permissions denied');
      return;
    }
    devicesRef.current = [];
    setDevices([]);
    setScanning(true);

    if (Platform.OS === 'android') {
      try { iHealthDeviceManagerModule.startDiscovery('ALL'); }
      catch (e) { console.log('Discovery failed:', e); }
    } else {
      const iosTypes = ['KN550', 'BP3L', 'BP5S', 'BP7S', 'AM3S', 'AM4',
        'PO3', 'HS2', 'HS2S', 'HS4S', 'BG5S', 'BG1S', 'PO1', 'ECG3'];
      let i = 0;
      const scanNext = () => {
        if (i < iosTypes.length) {
          try { iHealthDeviceManagerModule.startDiscovery(iosTypes[i]); }
          catch (e) { console.log(`Failed: ${iosTypes[i]}`, e); }
          i++;
          setTimeout(scanNext, 2000);
        }
      };
      setTimeout(scanNext, 2000);
    }
  };

  const stopScan = () => {
    try { iHealthDeviceManagerModule.stopDiscovery(); }
    catch (e) { console.log('Stop failed:', e); }
    setScanning(false);
  };

  return (
    <SafeAreaView style={styles.container}>
      <Text style={styles.title}>iHealth Scanner</Text>
      <Text style={styles.subtitle}>
        {scanning
          ? `Scanning... (${devices.length} found)`
          : `${devices.length} device(s) found`}
      </Text>

      {error && <Text style={styles.error}>{error}</Text>}

      <TouchableOpacity
        style={[styles.button, scanning && styles.buttonStop]}
        onPress={scanning ? stopScan : startScan}>
        <Text style={styles.buttonText}>
          {scanning ? 'Stop Scan' : 'Start Scan'}
        </Text>
      </TouchableOpacity>

      <FlatList
        data={devices}
        keyExtractor={item => item.mac}
        renderItem={({item}) => (
          <TouchableOpacity
            style={styles.deviceRow}
            onPress={() => {
              stopScan();
              onSelectDevice(item);
            }}>
            <View style={styles.deviceIcon}>
              <Text style={styles.deviceIconText}>
                {item.type.substring(0, 3)}
              </Text>
            </View>
            <View style={styles.deviceInfo}>
              <Text style={styles.deviceType}>{item.type}</Text>
              <Text style={styles.deviceMac}>{item.mac}</Text>
            </View>
            {item.rssi != null && (
              <Text style={styles.deviceRssi}>{item.rssi} dBm</Text>
            )}
            <Text style={styles.chevron}>{'>'}</Text>
          </TouchableOpacity>
        )}
        style={styles.list}
        contentContainerStyle={devices.length === 0 && styles.emptyList}
        ListEmptyComponent={
          <Text style={styles.emptyText}>
            {scanning
              ? 'Looking for iHealth devices...'
              : 'Tap "Start Scan" to find nearby iHealth devices'}
          </Text>
        }
      />
    </SafeAreaView>
  );
}

// ── App Root ─────────────────────────────────────────────────────────

function App() {
  const [selectedDevice, setSelectedDevice] = useState<Device | null>(null);

  return (
    <SafeAreaProvider>
      {selectedDevice ? (
        <DeviceScreen
          device={selectedDevice}
          onBack={() => setSelectedDevice(null)}
        />
      ) : (
        <ScannerScreen onSelectDevice={setSelectedDevice} />
      )}
    </SafeAreaProvider>
  );
}

// ── Styles ───────────────────────────────────────────────────────────

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: '#f5f5f5', paddingHorizontal: 16},
  title: {fontSize: 28, fontWeight: '700', color: '#1a1a1a', marginTop: 16},
  subtitle: {fontSize: 14, color: '#666', marginTop: 4, marginBottom: 16},
  error: {
    color: '#d32f2f', fontSize: 13, marginBottom: 8,
    backgroundColor: '#ffebee', padding: 8, borderRadius: 6,
  },
  button: {
    backgroundColor: '#2196F3', paddingVertical: 14,
    borderRadius: 10, alignItems: 'center', marginBottom: 16,
  },
  buttonStop: {backgroundColor: '#f44336'},
  buttonText: {color: '#fff', fontSize: 16, fontWeight: '600'},
  list: {flex: 1},
  emptyList: {flex: 1, justifyContent: 'center', alignItems: 'center'},
  emptyText: {color: '#999', fontSize: 15, textAlign: 'center'},
  deviceRow: {
    flexDirection: 'row', alignItems: 'center', backgroundColor: '#fff',
    padding: 14, borderRadius: 10, marginBottom: 8,
    shadowColor: '#000', shadowOffset: {width: 0, height: 1},
    shadowOpacity: 0.05, shadowRadius: 2, elevation: 1,
  },
  deviceIcon: {
    width: 44, height: 44, borderRadius: 22, backgroundColor: '#e3f2fd',
    justifyContent: 'center', alignItems: 'center', marginRight: 12,
  },
  deviceIconText: {fontSize: 12, fontWeight: '700', color: '#1565c0'},
  deviceInfo: {flex: 1},
  deviceType: {fontSize: 16, fontWeight: '600', color: '#1a1a1a'},
  deviceMac: {
    fontSize: 12, color: '#888', marginTop: 2,
    fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
  },
  deviceRssi: {fontSize: 12, color: '#999', marginLeft: 8},
  chevron: {fontSize: 18, color: '#ccc', marginLeft: 8},
  // Device screen
  backButton: {marginTop: 12, marginBottom: 4},
  backText: {color: '#2196F3', fontSize: 16},
  statusBadge: {
    fontSize: 13, color: '#f44336', marginTop: 8, marginBottom: 16,
    fontWeight: '600',
  },
  statusConnected: {color: '#4caf50'},
  sectionTitle: {
    fontSize: 16, fontWeight: '600', color: '#333',
    marginTop: 8, marginBottom: 8,
  },
  actionsRow: {flexGrow: 0, marginBottom: 12},
  actionButton: {
    backgroundColor: '#e3f2fd', paddingVertical: 10, paddingHorizontal: 16,
    borderRadius: 8, marginRight: 8,
  },
  actionDisabled: {backgroundColor: '#eee'},
  actionText: {color: '#1565c0', fontSize: 13, fontWeight: '600'},
  actionTextDisabled: {color: '#bbb'},
  logList: {flex: 1, marginTop: 4},
  logLine: {
    fontSize: 11, color: '#555', paddingVertical: 3,
    fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
  },
});

export default App;
