import React from 'react';
import {
  ActivityIndicator,
  FlatList,
  KeyboardAvoidingView,
  Platform,
  SafeAreaView,
  ScrollView,
  Text,
  TextInput,
  TouchableOpacity,
  View
} from "react-native";

import { CommandMode, Label_MediaType } from "react-native-bixolon-bgatelib";

import { styles } from "./components/Styles";
import { SelectItem } from "./components/SelectItem";
import { DiscoveryDevice } from "./components/DiscoveryDevice";
import { SearchDevices } from "./components/BgateConfig";
import { DeviceInfo } from "./components/DeviceInfo";
import { ResponseDeviceInfo } from "./components/Interfaces";
import { MPosController } from './components/MPosController';
import { MPosLabelController } from './components/MPosLabelController';

export default function App() {
  const posPrinterController = new MPosController();
  const labelPrinterController = new MPosLabelController();

  const [selected, setSelected] = React.useState(new DeviceInfo("", "", 4));
  const [interfaceString, setInterfaceString] = React.useState("Bluetooth");
  const [deviceType, setDeviceType] = React.useState('POS');
  const [bgateType, setBgateType] = React.useState("Direct");
  const [deviceId, setDeviceId] = React.useState(-1);
  const [deviceList, setDeviceList] = React.useState(new Array());
  const [processing, setProcessing] = React.useState(false);
  const [deviceIdList, setDeviceIdList] = React.useState(new Array<number>());
  const [running, setRunning] = React.useState(false);
  const [receivedText, setReceivedText] = React.useState("");
  const [sendText, setSendText] = React.useState("30 31 32 33 34 35 36 37 38 39 0d 0a");
  const [labelMediaType, setLabelMediaType] = React.useState(Label_MediaType.LABEL_MEDIA_TYPE_GAP);

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <View>
        <ScrollView>
          <Text style={styles.AppName}>Print Demo</Text>
          <SelectItem
            label="Select Interface"
            values={
              Platform.OS == "windows" 
              ? ["Bluetooth", "Network"]
              : ["Bluetooth", "Network", "USB"]
            }
            selectedValue={interfaceString}
            setSelectedValue={setInterfaceString}
          />
          <Devices />
          <SelectItem
            label="Device Type"
            values={["POS", "Label"]}
            selectedValue={deviceType}
            setSelectedValue={(value) => {
              setDeviceType(value);

              if (value === "POS") {
                setSendText("30 31 32 33 34 35 36 37 38 39 0d 0a");
              } else {
                setSendText("50 31 0d 0a");
              }
            }}
          />
          <SelectItem
            label="Mode"
            values={["Direct", "B-gate"]}
            selectedValue={bgateType}
            setSelectedValue={(value) => {
              if (value === "Direct") {
                setDeviceId(-1);
              } else {
                setDeviceId(0);
              }
              setBgateType(value);
            }}
          />
          <LabelMediaTypeSelectItem/>
          <DeviceId />
          <SampleButton />
          <View style={styles.container}>
            <Text style={styles.Title}>Received Data</Text>
            <View style={{ padding: 6, flexDirection: 'row' }}>
              <TextInput
                style={styles.textField}
                multiline={true}
                editable={false}
                selectTextOnFocus={false}
                value={receivedText} />
            </View>
          </View>
          <KeyboardAvoidingView behavior={Platform.select({ ios: 'padding', android: undefined })} style={styles.avoid}>
            <View style={styles.container}>
              <Text style={styles.Title}>Output</Text>
              <View style={{ padding: 6, flexDirection: 'row' }}>
                <TextInput
                  style={styles.textField}
                  multiline={true}
                  onChangeText={setSendText}
                  value={sendText} />
              </View>
            </View>
            <View style={styles.container}>
              <TouchableOpacity
                style={styles.deviceTestButton}
                onPress={running ? () => { } : async () => {
                  setRunning(true);
                  
                  let data = sendText.split(" ").map((e) => { return parseInt(e, 16); });

                  if (deviceType === "POS") {
                    posPrinterController.directIO(deviceId, data);
                  } else {
                    labelPrinterController.directIO(data);
                  }

                  setRunning(false);
                }
                }>
                <Text style={styles.BtnLabel}>Send data</Text>
              </TouchableOpacity>
            </View>
          </KeyboardAvoidingView>
        </ScrollView>
      </View>
    </SafeAreaView>
  );

  function Chip(device: ResponseDeviceInfo) {
    return (
      <TouchableOpacity
        style={[styles.listStyle, selected.devicename === device.item.devicename && styles.selectedChip,]}
        onPress={() => setSelected(new DeviceInfo(device.item.devicename, device.item.address, device.item.interfacetype))}
      >
        <Text style={styles.chip}>{device.item.devicename}</Text>
      </TouchableOpacity>
    );
  }

  function Devices() {
    if (processing)
      return (
        <View style={styles.container}>
          <View style={styles.viewRefresh}>
            <Text style={styles.Title}>Devices</Text>
          </View>
          <ActivityIndicator color={'orange'} />
        </View>
      )
    else if (deviceList.length == 0) {
      return (
        <View style={styles.container}>
          <View style={styles.viewRefresh}>
            <Text style={styles.Title}>Devices</Text>
          </View>
          <View style={styles.container}>
            <TouchableOpacity
              style={styles.chkBtn}
              onPress={async () => await DiscoveryDevice(interfaceString, setDeviceList, setProcessing)}>
              <Text style={styles.chkBtnLabel}>Discovery Devices</Text>
            </TouchableOpacity>
          </View>
        </View>
      );
    }
    else
      return (
        <View style={styles.container}>
          <View style={styles.viewRefresh}>
            <Text style={styles.Title}>Devices</Text>
          </View>
          <View style={styles.container}>
            <TouchableOpacity
              style={styles.chkBtn}
              onPress={async () => await DiscoveryDevice(interfaceString, setDeviceList, setProcessing)}>
              <Text style={styles.chkBtnLabel}>Discovery Devices</Text>
            </TouchableOpacity>

            <FlatList
              data={deviceList}
              renderItem={Chip}
              keyExtractor={item => item.devicename + Math.floor(Math.random() * 100)}
              horizontal={true} />
          </View>
        </View>
      )
  }

  function DeviceId() {
    return (
      <View style={styles.container}>
        <Text style={styles.Title}>Device Id</Text>
        <View style={{ padding: 6, flexDirection: 'row' }}>
          <Text style={styles.textInput}>{deviceId.toString()}</Text>
          <TouchableOpacity style={styles.SearchBtn}
            onPress={running ? () => { } : async () => {
              setDeviceIdList([]);
              setRunning(true);
              await SearchDevices(
                (bgateType === "B-gate") ? CommandMode.MPOS_MODE_DEFAULT : CommandMode.MPOS_MODE_BYPASS,
                selected.interfacetype,
                selected.address,
                setDeviceIdList
              );
              setRunning(false);
            }}>
            <Text style={styles.BtnLabel}>Search</Text>
          </TouchableOpacity>
        </View>
        <View style={styles.container}>
          <FlatList
            data={deviceIdList}
            renderItem={({ item }) => {
              return (
                <TouchableOpacity style={[styles.listStyle, item === deviceId && styles.selectedChip,]} onPress={() => setDeviceId(item)} >
                  <Text style={styles.chip}>{item.toString()}</Text>
                </TouchableOpacity>
              )
            }}
            keyExtractor={(item) => item.toString()}
            horizontal={true} />
        </View>
      </View>
    );
  }

  function LabelMediaTypeSelectItem() {
    if (deviceType == "Label") {
      return <SelectItem
          label="Label Media Type"
          values={["Black Mark", "Gap", "Continuous"]}
          selectedValue={getLabelMediaTypeString(labelMediaType)}
          setSelectedValue={(value) => {
            if (value == "Black Mark") {
              setLabelMediaType(Label_MediaType.LABEL_MEDIA_TYPE_BLACK_MARK);
            } else if (value == "Gap") {
              setLabelMediaType(Label_MediaType.LABEL_MEDIA_TYPE_GAP);
            } else {
              setLabelMediaType(Label_MediaType.LABEL_MEDIA_TYPE_CONTINUOUS);
            }
          }}
        />
    } else {
      return null;
    }
  }

  function getLabelMediaTypeString(labelMediaType : Label_MediaType) {
    switch(labelMediaType) {
      case Label_MediaType.LABEL_MEDIA_TYPE_GAP:
        return "Gap"
      case Label_MediaType.LABEL_MEDIA_TYPE_BLACK_MARK:
        return "Black Mark"
      case Label_MediaType.LABEL_MEDIA_TYPE_CONTINUOUS:
        return "Continuous"
    }
  }

  function SampleButton() {
    return (
      <View style={styles.container}>
        <View style={styles.row}>
          <View style={styles.col}>
            <TouchableOpacity
              style={styles.deviceTestButton}
              onPress={running ? () => { } : async () => {
                setRunning(true);
                var result = 1000;

                if (deviceType === "POS") {
                  result = await posPrinterController.openService(
                    selected.interfacetype,
                    selected.address,
                    bgateType === 'B-gate' ? CommandMode.MPOS_MODE_DEFAULT : CommandMode.MPOS_MODE_BYPASS,
                    deviceId,
                    // Output completed event
                    (deviceid: number) => {
                      console.log(`Device ID: ${deviceid} is output completed`);
                      setReceivedText(text => `${text}\nDevice ID: ${deviceid} is output completed`);
                    },
                    // Status update event
                    (deviceid: number, status: number) => {
                      console.log(`Device ID: ${deviceid} is status updated: ${status}`);
                      setReceivedText(text => `${text}\nDevice ID: ${deviceid} is status updated: ${status}`);
                    },
                    // Data event
                    (deviceId: number, byteArray: Array<number>) => {
                      console.log(`Device ID: ${deviceId} is received: ${byteArray}`);

                      const byteArrayToHexString = byteArray
                        .map((byte) => byte.toString(16))
                        .map((byteString) => byteString.padStart(2, '0'))
                        .join(' ')

                      setReceivedText(text => `${text}\nDevice ID: ${deviceId} is received: ${byteArrayToHexString}`);
                    }
                  );
                } else {
                  result = await labelPrinterController.openService(
                    selected.interfacetype,
                    selected.address,
                    bgateType === 'B-gate' ? CommandMode.MPOS_MODE_DEFAULT : CommandMode.MPOS_MODE_BYPASS,
                    deviceId,
                    // Output completed event
                    (deviceid: number) => {
                      console.log(`Device ID: ${deviceid} is output completed`);
                      setReceivedText(text => `${text}\nDevice ID: ${deviceid} is output completed`);
                    },
                    // Data event
                    (deviceId: number, byteArray: Array<number>) => {
                      console.log(`Device ID: ${deviceId} is received: ${byteArray}`);

                      const byteArrayToHexString = byteArray
                        .map((byte) => byte.toString(16))
                        .map((byteString) => byteString.padStart(2, '0'))
                        .join(' ')

                      setReceivedText(text => `${text}\nDevice ID: ${deviceId} is received: ${byteArrayToHexString}`);
                    }
                  );
                }

                setReceivedText(text => `${text}\nOpen service: ${result}`);
                setRunning(false);
              }
              }>
              <Text style={styles.BtnLabel}>Open service</Text>
            </TouchableOpacity>
          </View>
          <View style={styles.col}>
            <TouchableOpacity
              style={styles.deviceTestButton}
              onPress={running ? () => { } : async () => {
                setRunning(true);

                if (deviceType === "POS") {
                  await posPrinterController.print(deviceId);
                } else {
                  await labelPrinterController.printLabelSample(labelMediaType);
                  await labelPrinterController.printLabelBarcodes(labelMediaType);
                }

                setRunning(false);
              }
              }>
              <Text style={styles.BtnLabel}>Print sample</Text>
            </TouchableOpacity>
          </View>
        </View>
      </View>
    );
  }
}