import React, { Component } from "react"
import { Alert, Button, Image, Platform, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, useColorScheme, View } from "react-native"
import { launchImageLibrary, Asset } from "react-native-image-picker"
import { RadioButton } from "react-native-paper"
import { Switch } from 'react-native-switch'

import { NPrinter, NPrinterController, INPrinterControllerCallback, NPrintInfo, NResult } from 'react-native-nemonic-sdk'
import AsyncStorage from "@react-native-async-storage/async-storage"
import { NPrinterStatus } from "react-native-nemonic-sdk"
import { NCartridgeType } from "react-native-nemonic-sdk"
import Toast from "react-native-toast-message"
import { NBatteryStatus } from "react-native-nemonic-sdk"

class MainScreen extends Component implements INPrinterControllerCallback {

    private printerController: NPrinterController

    private selectedPrinter = new NPrinter()

    constructor(props: {}) {
        super(props)

        this.state = {
            imagePath: '',
            selectedPrinterName: 'No selected printer',
            connectDisconnectButtonName: 'Connect',
            copies: '1',
            printSpeedType: 'Low fast',
            isLastPageCut: true,
            enableDither: true,
            printerStatus: '',
            cartridgeType: '',
            printerName: '',
            batteryLevel: '',
            batteryStatus: ''
        }
        this.selectImage = this.selectImage.bind(this)

        this.printerController = new NPrinterController()
        this.printerController.setCallback(this)
    }

    render(): React.ReactNode {
        return (
            <SafeAreaView style={styles.container}>
                <View style={styles.column}>
                    <View style={styles.rowStretch}>
                        {this.getImageView()}
                        <View style={styles.column}>
                            {this.getSelectPrinterView()}
                            {this.getConnectView()}
                        </View>
                    </View>
                    {this.getPrintView()}
                </View>
                <ScrollView
                    contentInsetAdjustmentBehavior="automatic">
                    <View style={styles.columnStretch}>
                        {this.getPrintOptionView()}
                        {this.getPrinterStatusView()}
                        {this.getCartridgeTypeView()}
                        {this.getPrinterNameView()}
                        {this.getTemplateView()}
                        {this.getPowerView()}
                        <View style={{ height: 600 }} />
                    </View>
                </ScrollView>
            </SafeAreaView>
        )
    }

    componentDidMount(): void {
        this.updateSelectedPrinter()
    }

    componentDidUpdate(): void {
        this.updateSelectedPrinter()
    }

    private async updateSelectedPrinter() {
        var name = await AsyncStorage.getItem('selectedPrinterName') ?? ''
        var macAddress = await AsyncStorage.getItem('selectedPrinterMacAddress') ?? ''
        var type = Number(await AsyncStorage.getItem('selectedPrinterType') ?? '0')

        this.selectedPrinter.setName(name)
        this.selectedPrinter.setMacAddress(macAddress)
        this.selectedPrinter.setType(type)

        if (name.trim().length == 0) {
            this.setState({
                selectedPrinterName: 'No selected printer'
            })
        }
        else {
            this.setState({
                selectedPrinterName: name + '(' + macAddress + ')'
            })
        }
    }

    private selectImage() {
        launchImageLibrary(
            {
                mediaType: 'photo'
            },
            (response) => {
                if (response.didCancel) {
                    // Alert.alert('Cancel')
                }
                else if (response.errorMessage) {
                    Alert.alert('Error: ' + response.errorMessage)
                }
                else {
                    const uris: Asset[] = []
                    response.assets?.forEach((value) => uris.push(value))

                    uris.forEach((value) => {
                        if (value.uri != null) {
                            this.setState({
                                imagePath: value.uri!
                            })
                            // Alert.alert(value.uri!)
                        }
                    })
                }
            }
        )
    }

    private getImageView(): React.JSX.Element {
        return (
            <TouchableOpacity style={[{
                width: 150,
                height: 180,
                backgroundColor: 'powderblue',
            }]} onPress={this.selectImage}>
                <Image
                    source={
                        this.state.imagePath ? { uri: this.state.imagePath } : 0
                    }
                    style={[{
                        width: 150,
                        height: 180,
                        backgroundColor: 'red'
                    }]} />
            </TouchableOpacity>
        )
    }


    private getSelectPrinterView(): React.JSX.Element {
        return (
            <View style={styles.column}>
                <Text style={{ alignContent: 'stretch' }}>{this.state.selectedPrinterName}</Text>
                <View style={{ alignItems: 'stretch' }}>
                    <Button title='Select printer' onPress={() => this.props.navigation.navigate('SelectPrinter')} />
                </View>
            </View>
        )
    }

    private getConnectView(): React.JSX.Element {
        return (
            <View style={styles.columnStretch}>
                <Button
                    title={this.state.connectDisconnectButtonName}
                    onPress={async () => {
                        if (this.state.connectDisconnectButtonName == 'Connect') {
                            this.connect()
                        }
                        else {
                            this.disconnect()
                        }
                    }} />
            </View>
        )
    }


    private getPrintView(): React.JSX.Element {
        return (
            <View style={styles.rowStretch}>
                <TextInput
                    value={this.state.copies}
                    keyboardType='numeric'
                    placeholder='Copies(1~99)'
                    style={[{ width: 150 }]}
                    onChangeText={value => this.setState({ copies: value })} />
                <View style={styles.valueAlign}>
                    <Button title='Print' onPress={async () => this.print()} />
                </View>
            </View>
        )
    }

    private getPrintOptionView(): React.JSX.Element {
        return (
            <View style={styles.column}>
                {this.getPrintSpeedOptionView()}
                {this.getIsLastPageCutOptionView()}
                {this.getEnableDitherOptionView()}
            </View>
        )
    }

    private getPrintSpeedOptionView(): React.JSX.Element {
        return (
            <View style={styles.column && styles.center}>
                <RadioButton.Group
                    onValueChange={value => this.setState({ printSpeedType: value })}
                    value={this.state.printSpeedType}>
                    <View key={'Low fast'} style={styles.radioContainer}>
                        <RadioButton
                            value={'Low fast'}
                            uncheckedColor={'gray'}
                            color={'orange'}
                            status={this.state.printSpeedType === 'Low fast' ? 'checked' : 'unchecked'}
                            onPress={() => this.setState({ printSpeedType: 'Low fast' })}
                        />
                        <Text style={styles.radioButtonText}>Low fast</Text>
                    </View>
                    <View key={'Middle'} style={styles.radioContainer}>
                        <RadioButton
                            value={"Middle"}
                            uncheckedColor={'gray'}
                            color={'orange'}
                            status={this.state.printSpeedType === 'Middle' ? 'checked' : 'unchecked'}
                            onPress={() => this.setState({ printSpeedType: 'Middle' })}
                        />
                        <Text style={styles.radioButtonText}>Middle</Text>
                    </View>
                    <View key={'High slow'} style={styles.radioContainer}>
                        <RadioButton
                            value={"High slow"}
                            uncheckedColor={'gray'}
                            color={'orange'}
                            status={this.state.printSpeedType === 'High slow' ? 'checked' : 'unchecked'}
                            onPress={() => this.setState({ printSpeedType: 'High slow' })}
                        />
                        <Text style={styles.radioButtonText}>High slow</Text>
                    </View>
                </RadioButton.Group>
            </View>
        )
    }

    private getIsLastPageCutOptionView(): React.JSX.Element {
        return (
            <View style={styles.valueAlign}>
                <Text style={styles.valueTitle}>Last page cut</Text>
                <Switch
                    value={this.state.isLastPageCut}
                    onValueChange={(value) => this.setState({ isLastPageCut: value })}
                    changeValueImmediately={true}
                    innerCircleStyle={{ alignItems: 'center', justifyContent: 'center' }}
                    renderActiveText={false}
                    renderInActiveText={false}
                    switchRightPx={2}
                    switchLeftPx={2}
                    switchBorderRadius={30} />
            </View>
        )
    }

    private getEnableDitherOptionView(): React.JSX.Element {
        return (
            <View style={styles.valueAlign}>
                <Text style={styles.valueTitle}>Dither</Text>
                <Switch
                    value={this.state.enableDither}
                    onValueChange={(value) => this.setState({ enableDither: value })}
                    changeValueImmediately={true}
                    innerCircleStyle={{ alignItems: 'center', justifyContent: 'center' }}
                    renderActiveText={false}
                    renderInActiveText={false}
                    switchRightPx={2}
                    switchLeftPx={2}
                    switchBorderRadius={30} />
            </View>
        )
    }

    private getPrinterStatusView(): React.JSX.Element {
        return (
            <View style={styles.valueAlign}>
                <Text style={styles.valueTitle}>Printer status</Text>
                <Text style={styles.valueValue}>{this.state.printerStatus}</Text>
                <View style={styles.valueButton}>
                    <Button title='Get' onPress={async () => this.getPrinterStatus()} />
                </View>
            </View>
        )
    }

    private getCartridgeTypeView(): React.JSX.Element {
        return (
            <View style={styles.valueAlign}>
                <Text style={styles.valueTitle}>Cartridge type</Text>
                <Text style={styles.valueValue}>{this.state.cartridgeType}</Text>
                <View style={styles.valueButton}>
                    <Button title='Get' onPress={async () => this.getCartridgeType()} />
                </View>
            </View>
        )
    }

    private getPrinterNameView(): React.JSX.Element {
        return (
            <View style={styles.valueAlign}>
                <Text style={styles.valueTitle}>Printer name</Text>
                <Text style={styles.valueValue}>{this.state.printerName}</Text>
                <View style={styles.valueButton}>
                    <Button title='Get' onPress={async () => this.getPrinterName()} />
                </View>
            </View>
        )
    }

    private getTemplateView(): React.JSX.Element {
        return (
            <View style={styles.column}>
                <Text style={styles.valueTitle}>Template</Text>
                <View style={styles.rowStretch && styles.valueAlign}>
                    <Button title='Set' onPress={async () => this.setTemplate()} />
                    <Button title='Delete' onPress={async () => this.deleteTemplate()} />
                </View>
            </View>
        )
    }

    private getPowerView(): React.JSX.Element {
        return (
            <View style={styles.columnStretch}>
                <Text style={styles.valueMainTitle}>Power</Text>
                {this.getBatteryLevelView()}
                {this.getBatteryStatusView()}
            </View>
        )
    }

    private getBatteryLevelView(): React.JSX.Element {
        return (
            <View style={styles.valueAlign}>
                <Text style={styles.valueTitle}>Battery level</Text>
                <Text style={styles.valueValue}>{this.state.batteryLevel}</Text>
                <View style={styles.valueButton}>
                    <Button title='Get' onPress={async () => this.getBatteryLevel()} />
                </View>
            </View>
        )
    }

    private getBatteryStatusView(): React.JSX.Element {
        return (
            <View style={styles.valueAlign}>
                <Text style={styles.valueTitle}>Battery status</Text>
                <Text style={styles.valueValue}>{this.state.batteryStatus}</Text>
                <View style={styles.valueButton}>
                    <Button title='Get' onPress={(async) => this.getBatteryStatus()} />
                </View>
            </View>
        )
    }

    public disconnected() {
        this.setState({
            connectDisconnectButtonName: 'Connect'
        })

        this.showToast('Disconnected')
    }

    public printProgress(index: number, total: number, result: number) {

    }

    public printComplete(result: number) {

    }

    private async connect() {
        let result = await this.printerController.connect(this.selectedPrinter, 'org.reactjs.native.example.NemonicSdkReactNative')
        if (result == NResult.OK) {
            this.setState({
                connectDisconnectButtonName: 'Disconnect'
            })
            this.showToast('Connected')
        }
        else {
            this.setResult(result)
        }
    }

    private disconnect() {
        this.printerController.disconnect()
        this.setState({
            connectDisconnectButtonName: 'Connect'
        })

        this.showToast('Disconnected')
    }

    private async print() {
        let printInfo = new NPrintInfo()

        let quality = 0
        switch (this.state.printSpeedType) {
            case 'Low fast':
                quality = 0
                break
            case 'Middle':
                quality = 1
                break
            case 'High slow':
                quality = 2
                break
        }

        printInfo.addImageUrl(this.state.imagePath)
            .setCopies(Number(this.state.copies))
            .setPrintQulity(quality)
            .setEnableLastPageCut(this.state.isLastPageCut)
            .setEnableDither(this.state.enableDither)
        let result = await this.printerController.print(printInfo)
        this.setResult(result)


        // const r = await fetch(this.state.imagePath)
        // const ib = await r.blob()
        // let fr = new FileReader()
        // fr.readAsArrayBuffer(ib)

        // let Self = this
        // fr.onload = async function () {
        //     let arrayBuffer = fr.result as ArrayBuffer
        //     let byteArray = new Uint8Array(arrayBuffer)
        //     console.log('CCCCCCCC')
        //     console.log(byteArray.length)
        //     printInfo.addImageWithUint8Array(byteArray)
        //         .setPrintQulity(quality)
        //         .setCopies(Number(Self.state.copies))
        //         .setEnableLastPageCut(Self.state.isLastPageCut)
        //         .setEnableDither(Self.state.enableDither)

        //     let result = await Self.printerController.print(printInfo)
        //     Self.setResult(result)
        // }
    }

    private async getPrinterStatus() {

        this.setState({
            printerStatus: ''
        })

        let result = await this.printerController.getPrinterStatus()
        if (result >= 0) {
            let status = ''
            switch (result) {
                case NPrinterStatus.OK:
                    status = 'OK'
                    break
                case NPrinterStatus.COVER_OPENED:
                    status = 'Cover opened'
                    break
                case NPrinterStatus.OUT_OF_PAPER:
                    status = 'Out of paper'
                    break
                case NPrinterStatus.PAPER_JAM:
                    status = 'Paper jam'
                    break
                case NPrinterStatus.OVERHEAT:
                    status = 'Overheat'
                    break
                default:
                    status = result.toString()
                    break
            }
            this.setState({
                printerStatus: status
            })
        }
        else {
            this.setResult(result)
        }
    }

    private async getCartridgeType() {
        this.setState({
            cartridgeType: ''
        })

        let result = await this.printerController.getCartridgeType()
        let cartridgeType = ''

        if (result >= 0) {
            let type = NCartridgeType.getCartridgeType(result)
            switch (type) {
                case NCartridgeType.white:
                    cartridgeType = 'White'
                    break
                case NCartridgeType.yellow:
                    cartridgeType = 'Yellow'
                    break
                case NCartridgeType.green:
                    cartridgeType = "Green"
                    break
                case NCartridgeType.blue:
                    cartridgeType = 'Blue'
                    break
                case NCartridgeType.pink:
                    cartridgeType = 'Pink'
                    break
                case NCartridgeType.l1:
                    cartridgeType = 'L1'
                    break
                case NCartridgeType.l2:
                    cartridgeType = 'L2'
                    break
                case NCartridgeType.l3:
                    cartridgeType = 'L3'
                    break
                case NCartridgeType.l4:
                    cartridgeType = 'L4'
                    break
                case NCartridgeType.l5:
                    cartridgeType = 'L5'
                    break
                case NCartridgeType.l6:
                    cartridgeType = 'L6'
                    break
                case NCartridgeType.l7:
                    cartridgeType = 'L7'
                    break
                case NCartridgeType.l8:
                    cartridgeType = 'L8'
                    break
                case NCartridgeType.m1:
                    cartridgeType = 'm1'
                    break
                case NCartridgeType.m2:
                    cartridgeType = 'm2'
                    break
                case NCartridgeType.m3:
                    cartridgeType = 'm3'
                    break
                case NCartridgeType.m4:
                    cartridgeType = 'm4'
                    break
                case NCartridgeType.m5:
                    cartridgeType = 'm5'
                    break
                case NCartridgeType.m6:
                    cartridgeType = 'm6'
                    break
                case NCartridgeType.m7:
                    cartridgeType = 'm7'
                    break
                case NCartridgeType.m8:
                    cartridgeType = 'm8'
                    break
                case NCartridgeType.question:
                    cartridgeType = '?'
                    break
                case NCartridgeType.n:
                    cartridgeType = 'N'
                    break
                case NCartridgeType.none:
                    cartridgeType = "X"
                    break
                default:
                    cartridgeType = result.toString()
                    break
            }
            this.setState({
                cartridgeType: cartridgeType
            })
        }
        else {
            this.setResult(result)
        }
    }

    private async getPrinterName() {
        this.setState({
            printerName: ''
        })

        let resultString = await this.printerController.getPrinterName()
        let result = resultString.getResult()
        let value = resultString.getValue()

        if (result == NResult.OK) {
            this.setState({
                printerName: value
            })
        }

        this.setResult(result)
    }

    private async setTemplate() {
        let result = await this.printerController.setTemplateWithUrl(this.state.imagePath, true, this.state.enableDither)
        this.setResult(result)


        // const r = await fetch(this.state.imagePath)
        // const ib = await r.blob()
        // let fr = new FileReader()
        // fr.readAsArrayBuffer(ib)

        // let Self = this
        // fr.onload = async function () {
        //     let arrayBuffer = fr.result as ArrayBuffer
        //     let byteArray = new Uint8Array(arrayBuffer)

        //     let result = await Self.printerController.setTemplateWithUint8Array(byteArray, true, Self.state.enableDither)
        //     Self.setResult(result)
        // }
    }

    private async deleteTemplate() {
        let result = await this.printerController.clearTemplate()
        this.setResult(result)
    }

    private async getBatteryLevel() {
        this.setState({
            batteryLevel: ''
        })

        let result = await this.printerController.getBatteryLevel()

        if (result >= 0) {
            this.setState({
                batteryLevel: result.toString()
            })
            this.showToast('Success')
        }
        else {
            this.setResult(result)
        }
    }

    private async getBatteryStatus() {
        this.setState({
            batteryStatus: ''
        })

        let result = await this.printerController.getBatteryStatus()

        if (result >= 0) {
            let status = ''
            switch (result) {
                case NBatteryStatus.NO_CHARGING:
                    status = 'No charging'
                    break
                case NBatteryStatus.LOW_NO_CHARGING:
                    status = 'Low & No charging'
                    break
                case NBatteryStatus.CHARGING:
                    status = 'Charging'
                    break
                case NBatteryStatus.LOW_CHARGING:
                    status = 'Low & Charging'
                    break
                default:
                    break
            }

            this.setState({
                batteryStatus: status
            })
        }
        else {
            this.setResult(result)
        }
    }

    private setResult(result: number) {
        switch (result) {
            case NResult.OK:
                this.showToast("Success")
                break
            default:
                this.showToast(result.toString())
                break
        }
    }

    private showToast(content: string) {
        Toast.show({
            text1: 'Info',
            text2: content,
            position: 'bottom'
        })
    }
}

export default MainScreen

const styles = StyleSheet.create({
    container: {
        flex: 1
    },
    sectionContainer: {
        marginTop: 32,
        paddingHorizontal: 24,
    },
    sectionTitle: {
        fontSize: 24,
        fontWeight: '600',
    },
    sectionDescription: {
        marginTop: 8,
        fontSize: 18,
        fontWeight: '400',
    },
    highlight: {
        fontWeight: '700',
    },
    row: {
        flexDirection: 'row',
        flexWrap: 'wrap'
    },
    column: {
        flexDirection: 'column',
        flexWrap: 'wrap'
    },
    rowStretch: {
        flexDirection: 'row',
        alignSelf: 'stretch',
        alignItems: 'stretch',
        alignContent: 'stretch'
    },
    columnStretch: {
        flexDirection: 'column',
        alignSelf: 'stretch',
        alignItems: 'stretch'
    },
    center: {
        alignItems: 'center'
    },
    valueMainTitle: {
        fontSize: 25,
        fontWeight: 'bold'
    },
    valueTitle: {
        minWidth: 100,
        maxWidth: 500,
        height: 50,
        textAlignVertical: 'center',
        alignContent: 'space-around',
        fontSize: 20
    },
    valueValue: {
        textAlignVertical: 'center',
        alignContent: 'space-around'
    },
    valueAlign: {
        flexDirection: 'row',
        flexWrap: 'wrap-reverse',
        alignSelf: 'stretch',
        alignItems: 'stretch',
        justifyContent: 'space-between'
    },
    valueButton: {
        width: 80
    },
    radioContainer: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        alignItems: 'center',
        backgroundColor: '#ffffff',
        minHeight: 48,
        paddingStart: 8,
        paddingEnd: 8,
        borderRadius: 4,
        marginBottom: 4
    },
    radioButtonText: {
        color: 'black'
    }
})