using CommunityToolkit.Maui.Views;
using System.Text;
using DeviceInfo = SII.SDK.Maui.Printer.DeviceInfo;
using SII.SDK.Maui.Printer;

namespace Sample;

public partial class MainPage : ContentPage
{
    private Function _function;

    public DeviceInfo SelectedDevice { get; set; }

    public MainPage()
    {
        InitializeComponent();
        _function = new Function();
        _function.DeviceSearchCompletedEvent += this.DeviceSearchCompleted;

        this.VersionLabel.Text = $"SDK Version: {_function.GetVersion()} ";
    }

    private async void SearchButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);
        string result = await _function.SearchDeviceSample(GetSelectedPortType());
        if (result != "")
        {
            Alert("ERROR", result);
        }
    }

    private async void ConnectButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);

        // Start communication
        string result = await _function.ConnectSampleAsync(GetSelectedDeviceModel(), SelectedDevice);
        // Whether callback starting or not.
        if (this.CallbackSwitch.IsToggled)
        {
            // Start callback
            await _function.StatusCallbackSampleAsync(this.StatusChanged);
            await _function.BarcodeScannerCallbackSampleAsync(this.ScannerOnline, this.ScannerOffline, this.ScannedData);
        }
        if (result != "")
        {
            Alert("ERROR", result);
        }
        else
        {
            Alert("INFO", "Connect success");
        }
    }

    private async void DisconnectButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);

        // Cancel callback
        await _function.StatusCallbackSampleAsync(null);
        await _function.BarcodeScannerCallbackSampleAsync(null, null, null);
        this.StatusLabel.Text = "-";
        this.ScannerStatusLabel.Text = "-";
        this.ScannedDataLabel.Text = "-";
        // End communication
        string result = await _function.DisonnectSampleAsync();
        if (result != "")
        {
            Alert("ERROR", result);
        }
        else
        {
            Alert("INFO", "Disconnect success");
        }


    }

    private async void StandardSampleButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);

        string result = await _function.StandardModePrintSampleAsync();
        if (result != "")
        {
            Alert("ERROR", result);
        }
        else
        {
            Alert("INFO", "Standard Mode Sample success");
        }
    }

    private async void PageSampleButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);

        string result = await _function.PageModePrintSampleAsync();
        if (result != "")
        {
            Alert("ERROR", result);
        }
        else
        {
            Alert("INFO", "Page Mode Sample success");
        }
    }

    private async void DisplaySampleButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);
        _total = 0;
        _itemIndex = 0;

        string result = await _function.BeginPaymentSampleAsync(_total);
        if (result != "")
        {
            Alert("ERROR", result);
            return;
        }

        await Task.Delay(1000);

        for (int i = 0; i < 5; i++)
        {
            PickAnItem(_function.GetCurrentLanguage());

            result = await _function.RegisterItemSampleAsync(_total, _itemName, _itemPrice);
            if (result != "")
            {
                Alert("ERROR", result);
                return;
            }

            await Task.Delay(500);
        }

        await Task.Delay(1000);

        CalculateTotal();

        result = await _function.FinishPaymentSampleAsync(_total, _paid, _change);
        if (result != "")
        {
            Alert("ERROR", result);
            return;
        }

        await Task.Delay(3000);

        result = await _function.StandbySampleAsync();
        if (result != "")
        {
            Alert("ERROR", result);
            return;
        }

        Alert("INFO", "Display Sample success");
    }

    private async void SmartLabelSampleButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);

        string result = await _function.SmartLabelSampleAsync();
        if (result != "")
        {
            Alert("ERROR", result);
        }
        else
        {
            Alert("INFO", "Smart Label Sample success");
        }
    }

    private async void SendDataFileSampleButton_Clicked(object sender, EventArgs e)
    {
        try
        {
            await _function.CheckStoragePermissions();

            // Show file picker
            var customFileType = new FilePickerFileType(
                new Dictionary<DevicePlatform, IEnumerable<string>>
                {
                    { DevicePlatform.iOS, new[] { "com.microsoft.bmp", "public.jpeg", "public.png", "public.text","public.data", "public.script" } }, // UTType values
                    { DevicePlatform.Android, new[] { "image/*", "application/octet-stream", "text/html", "text/plain" } }, // MIME type

                });
            PickOptions options = new()
            {
                PickerTitle = "Please select a file",
                FileTypes = customFileType,
            };
            FileResult fileResult = await FilePicker.Default.PickAsync(options);

            _ = DisplayPopup(true);

            if (fileResult != null)
            {
                using (Stream stream = await fileResult.OpenReadAsync())
                {
                    string result = await _function.SendDataFileSampleAsync(fileResult.FullPath);
                    if (result != "")
                    {
                        Alert("ERROR", result);
                    }
                    else
                    {
                        Alert("INFO", "Send Data File success");
                    }
                }
            }
            else
            {
                Alert("ERROR", $"SendDataFileSample Error : {PrinterException.ERROR_INVALID_PARAM}");
            }
        }
        catch(Exception)
        {
            Alert("ERROR", $"SendDataFileSample Error : {PrinterException.ERROR_INVALID_PARAM}");
        }
    }

    private async void PrintPDFSampleButton_Clicked(object sender, EventArgs e)
    {
        try
        {
            await _function.CheckStoragePermissions();

            // Show file picker
            var customFileType = new FilePickerFileType(
                new Dictionary<DevicePlatform, IEnumerable<string>>
                {
                    { DevicePlatform.iOS, new[] { "com.adobe.pdf" } }, // UTType values
                    { DevicePlatform.Android, new[] { "application/pdf"} }, // MIME type

                });
            PickOptions options = new()
            {
                PickerTitle = "Please select a PDF file",
                FileTypes = customFileType,
            };
            FileResult fileResult = await FilePicker.Default.PickAsync(options);

            _ = DisplayPopup(true);

            if (fileResult != null)
            {
                using (Stream stream = await fileResult.OpenReadAsync())
                {
                    string result = await _function.PrintPDFSampleAsync(fileResult.FullPath);
                    if (result != "")
                    {
                        Alert("ERROR", result);
                    }
                    else
                    {
                        Alert("INFO", "Print PDF success");
                    }
                }
            }
            else
            {
                Alert("ERROR", $"PrintPDF Sample Error : {PrinterException.ERROR_INVALID_PARAM}");
            }
        }
        catch (Exception)
        {
            Alert("ERROR", $"PrintPDF Sample Error : {PrinterException.ERROR_INVALID_PARAM}");
        }
    }

    private async void OpenDrawerSampleButton_Clicked(object sender, EventArgs e)
    {
        _ = DisplayPopup(true);

        string result = await _function.OpenDrawerSampleAsync();
        if (result != "")
        {
            Alert("ERROR", result);
        }
        else
        {
            Alert("INFO", "Open Drawer Sample success");
        }
    }

    public void DeviceSearchCompleted(DeviceInfo[] devices)
    {
        Dispatcher.Dispatch(async () =>
        {
            await DisplayPopup(false);

            if (devices != null && devices.Length != 0)
            {
                Dictionary<string, DeviceInfo> deviceList = new Dictionary<string, DeviceInfo>();
                foreach (var device in devices)
                {
                    string key = "";
                    switch (device.PortType)
                    {
                        case PortType.PORT_TYPE_BLUETOOTH:
                            key = $"{device.DeviceName}({device.BluetoothAddress})";
                            break;
                        case PortType.PORT_TYPE_TCP:
                            key = $"{device.IpAddress}({device.MacAddress})";
                            break;
                        case PortType.PORT_TYPE_USB:
                            key = $"{device.DeviceName}({device.DevicePath})";
                            break;
                        default:
                            continue;
                    }

                    deviceList.Add(key, device);
                }
                string selectDevice = await DisplayActionSheet("Select Device", "Cancel", null, deviceList.Keys.ToArray());

                if (deviceList.ContainsKey(selectDevice))
                {
                    SelectedDevice = deviceList[selectDevice];
                    SelectedDeviceLabel.Text = selectDevice;
                }
            }
            else
            {
                Alert("ERROR", "Device is not found.");
            }
        });
    }

    // Sample of statusChangedEventHandler delegate of SetStatusChangedEventHandler
    public void StatusChanged(int status)
    {
        Dispatcher.Dispatch(() =>
        {
            StatusLabel.Text = $"0x{status:X8}";
        });
    }

    // Sample of barcodeScannerChangedOnlineEventHandler delegate of SetBarcodeScannerChangedOnlineEventHandler
    public void ScannerOffline()
    {
        Dispatcher.Dispatch(() =>
        {
            ScannerStatusLabel.Text = "Offline";
        });
    }

    // Sample of barcodeScannerChangedOfflineEventHandler delegate of SetBarcodeScannerChangedOfflineEventHandler
    public void ScannerOnline()
    {
        Dispatcher.Dispatch(() =>
        {
            ScannerStatusLabel.Text = "Online";
        });
    }

    // Sample of barcodeScannerReadDataEventHandler delegate of SetBarcodeScannerReadDataEventHandler
    public void ScannedData(byte[] scannedData)
    {
        Dispatcher.Dispatch(() =>
        {
            try
            {
                string data;
                if (this.EncodeSwitch.IsToggled)
                {
                    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                    data = Encoding.GetEncoding("Shift_JIS").GetString(scannedData);
                }
                else
                {
                    data = BitConverter.ToString(scannedData).Replace("-", string.Empty);
                }
                ScannedDataLabel.Text = data;
            }
            catch (Exception)
            {
                ScannedDataLabel.Text = "Encoding failed.";
            }
        });
    }

    private DeviceModel GetSelectedDeviceModel()
    {
        switch (DeviceModelPicker.SelectedIndex)
        {
            case 0:
                return DeviceModel.DEVICE_MODEL_MP_B21L;
            case 1:
                return DeviceModel.DEVICE_MODEL_SLP720RT;
            case 2:
                return DeviceModel.DEVICE_MODEL_MP_B30L;
            case 3:
                // Includes RP-G10
                return DeviceModel.DEVICE_MODEL_RP_F10;
            case 4:
                return DeviceModel.DEVICE_MODEL_MP_B30;
            case 5:
                return DeviceModel.DEVICE_MODEL_MP_B20;
            case 6:
                return DeviceModel.DEVICE_MODEL_RP_E10;
            case 7:
                return DeviceModel.DEVICE_MODEL_RP_D10;
            case 8:
                return DeviceModel.DEVICE_MODEL_DSP_A01;
            case 9:
                return DeviceModel.DEVICE_MODEL_MP_A40;
            default:
                return DeviceModel.DEVICE_MODEL_RP_E10;
        }
    }

    private PortType GetSelectedPortType()
    {
        switch (SearchTypePicker.SelectedIndex)
        {
            case 0:
                return PortType.PORT_TYPE_BLUETOOTH;
            case 1:
                return PortType.PORT_TYPE_TCP;
            case 2:
                return PortType.PORT_TYPE_USB;
            default:
                return PortType.PORT_TYPE_BLUETOOTH;
        }
    }

    #region Used in the display sample.
    private int _total = 0;
    private int _paid = 0;
    private int _change = 0;
    private int _itemIndex = 0;
    private string _itemName = "";
    private int _itemPrice = 0;

    private string[] _itemNames_en = new string[5]
    {
            "BROCCOLI ",
            "BANANA ",
            "POTATO ",
            "GRAPES ",
            "PEAS "
    };

    private string[] _itemNames_ja = new string[5]
{
            "ブロッコリー ",
            "バナナ ",
            "ポテト ",
            "ブドウ ",
            "エンドウマメ "
};

    private int[] _itemPrices = new int[5]
    {
            132,
            186,
            391,
            116,
            100
    };

    private void PickAnItem(System.String language)
    {
        // Change the display content to match the language of the device.
        _itemName =
            (language.Contains("en")) ?         // Pick an item name
            _itemNames_en[_itemIndex]
            : _itemNames_ja[_itemIndex];

        _itemPrice = _itemPrices[_itemIndex];   // Pick an item price	
        _itemIndex = (_itemIndex + 1) % 5;
        _total += _itemPrice;                   // Calculate total
    }

    private void CalculateTotal()
    {
        _paid = ((_total + 999) / 1000) * 1000;
        _change = _paid - _total;
    }
    #endregion

    public void Alert(string title, string message)
    {
        Dispatcher.Dispatch(async () =>
        {
            await DisplayPopup(false);
            _ = DisplayAlert(title, message, "OK");
        });
    }

    private IndicatorPopup indicatorPopup = null;
    public async Task DisplayPopup(bool isDisplay)
    {
        if (isDisplay)
        {
            if (indicatorPopup == null)
            {
                indicatorPopup = new IndicatorPopup();
                this.ShowPopup(indicatorPopup);
            }
        }
        else
        {
            if (indicatorPopup != null)
            {
                await indicatorPopup.CloseAsync();
                indicatorPopup = null;
            }
        }
    }
}


