using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

using CSVDownloader.Code;
using CSVDownloader.Store.CreditCSVData;
using CSVDownloader.Store.QRCSVData;
using CSVDownloader.Exceptions;

using ExpectedConditions = OpenQA.Selenium.Support.UI.ExpectedConditions;

namespace CSVDownloader.Web {
    class DaitoController : WebController {

        private readonly String url_ = "https://crevation.net";

        private readonly String home_url_ = "https://crevation.net/";

        private readonly String filename_credit = "daito_credit.csv";
        private readonly String filename_qr = "daito_qr.csv";

        private enum XpathKey {
            INPUT_LOGIN_USERNAME,
            INPUT_LOGIN_PASSWORD,
            BUTTON_MENU,
            BUTTON_KESSAI_KANRI,
            BUTTON_CREDIT_KESSAI,
            BUTTON_QR_KESSAI,
            INPUT_TARGET_FROM,
            INPUT_TARGET_TO,
            BUTTON_DOWNLOAD_CSV,
            BUTTON_LOGOUT,
        };

        private IDictionary<XpathKey, string> xpath_map_ = new Dictionary<XpathKey, string>()
        {
            {XpathKey.INPUT_LOGIN_USERNAME,@"//*[@id='wrapper']/div/div/div/div/div[2]/form/fieldset/div[1]/input" },
            {XpathKey.INPUT_LOGIN_PASSWORD,@"//*[@id='wrapper']/div/div/div/div/div[2]/form/fieldset/div[2]/input" },
            {XpathKey.BUTTON_MENU,@"//*[@id='js-show-popup']" },
            {XpathKey.BUTTON_KESSAI_KANRI,@"//*[@id='side-menu']/li[4]/a" },
            {XpathKey.BUTTON_CREDIT_KESSAI,@"//*[@id='side-menu']/li[4]/ul/li[1]/a" },
            {XpathKey.BUTTON_QR_KESSAI,@"//*[@id='side-menu']/li[4]/ul/li[2]/a" },
            {XpathKey.INPUT_TARGET_FROM,@"//*[@id='settlementTimeFrom']" },
            {XpathKey.INPUT_TARGET_TO,@"//*[@id='settlementTimeTo']" },
            {XpathKey.BUTTON_DOWNLOAD_CSV,@"//*[@id='submitCreateCsv']" },
            {XpathKey.BUTTON_LOGOUT,@"//*[@id='side-menu']/li[11]/a" },

        };


        public DaitoController(ChromeDriver driver) : base(driver) {
            agent_ = CreditAgent.Daito;
        }

        public override ResultCode Login(LoginInfo info) {
            bool enter = true;


            try {
                driver_.Navigate().GoToUrl(url_);
                Send(xpath_map_[XpathKey.INPUT_LOGIN_USERNAME], info.user_name);
                Send(xpath_map_[XpathKey.INPUT_LOGIN_PASSWORD], info.password, enter);

                // ログイン後のメニューボタンが表示されることを確認する。
                wait_.Until(ExpectedConditions.ElementExists(By.XPath(xpath_map_[XpathKey.BUTTON_MENU])));

            } catch (Exception e) {
                logger_.Error(e.Message);
                return ResultCode.NG;
            }
            return ResultCode.OK;
        }

        public override ResultCode Download(DateTime from, DateTime to) {
            // クレジットカード承認結果一覧画面に移行
            Click(xpath_map_[XpathKey.BUTTON_MENU]);
            Click(xpath_map_[XpathKey.BUTTON_KESSAI_KANRI]);
            Click(xpath_map_[XpathKey.BUTTON_CREDIT_KESSAI]);

            // 承認処理日のFrom-Toを入力
            const String date_format = "yyyy年MM月dd日";
            Send(xpath_map_[XpathKey.INPUT_TARGET_FROM], from.ToString(date_format));
            Send(xpath_map_[XpathKey.INPUT_TARGET_TO], to.ToString(date_format));

            // CSV吐き出しボタンをクリックし、CSVをダウンロード
            wait_.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpath_map_[XpathKey.BUTTON_DOWNLOAD_CSV])));

            Click(xpath_map_[XpathKey.BUTTON_DOWNLOAD_CSV]);
            WaitForDownload(filename_credit);

            // QR決済結果結果一覧画面に移行
            Click(xpath_map_[XpathKey.BUTTON_MENU]);
            Click(xpath_map_[XpathKey.BUTTON_KESSAI_KANRI]);
            Click(xpath_map_[XpathKey.BUTTON_QR_KESSAI]);

            // 承認処理日のFrom-Toを入力
            Send(xpath_map_[XpathKey.INPUT_TARGET_FROM], from.ToString(date_format));
            Send(xpath_map_[XpathKey.INPUT_TARGET_TO], to.ToString(date_format));

            // CSV吐き出しボタンをクリックし、CSVをダウンロード
            wait_.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpath_map_[XpathKey.BUTTON_DOWNLOAD_CSV])));

            Click(xpath_map_[XpathKey.BUTTON_DOWNLOAD_CSV]);
            WaitForDownload(filename_qr);


            return ResultCode.OK;
        }

        public override ResultCode Logout() {

            driver_.Navigate().GoToUrl(home_url_);

            Click(xpath_map_[XpathKey.BUTTON_MENU]);
            Click(xpath_map_[XpathKey.BUTTON_LOGOUT]);

            wait_.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath_map_[XpathKey.INPUT_LOGIN_USERNAME])));

            return ResultCode.OK;
        }


        public override List<CreditCSVData> GetCreditCSVDataList() {


            var result_list = new List<CreditCSVData>();


            var list = GetFileContents(filename_credit);

            bool failed_flg = false;
            var failed_parking_name_hs_table = new HashSet<String>();

            foreach (var line in list) {
                var parking_name = line[(int)CreditCSVDataDaito.ColName.ParkingName];
                try {
                    result_list.Add(new CreditCSVDataDaito() {
                        spot_id = GetSpotID(parking_name),
                        parking_name = parking_name,
                        developer = line[(int)CreditCSVDataDaito.ColName.Developer],
                        adjust_type = line[(int)CreditCSVDataDaito.ColName.AdjustType],
                        fee_type = line[(int)CreditCSVDataDaito.ColName.FeeType],
                        reception_datetime = DateTime.Parse(line[(int)CreditCSVDataDaito.ColName.ReceptionDatetime]),
                        amount = int.Parse(line[(int)CreditCSVDataDaito.ColName.Amount]),
                        reception_no = line[(int)CreditCSVDataDaito.ColName.ReceptionNo],
                        response_no = line[(int)CreditCSVDataDaito.ColName.ResponseNo],
                        error_code1 = line[(int)CreditCSVDataDaito.ColName.ErrorCode1],
                        error_code2 = line[(int)CreditCSVDataDaito.ColName.ErrorCode2]
                    });

                } catch (ArgumentException) {

                    failed_parking_name_hs_table.Add(parking_name);
                    failed_flg = true;
                    continue;
                }
            }

            if (failed_flg) {
                var error_list = new List<Store.ParkingCreditCardAgenciesSpotIDError>();
                logger_.Error("失敗駐車場名");
                foreach (var ele in failed_parking_name_hs_table) {
                    error_list.Add(new Store.ParkingCreditCardAgenciesSpotIDError() {
                        creditcard_agencies_id = CreditAgenciesMap.GetID(agent_),
                        creditcard_agencies_spot_name = ele
                    });
                    logger_.Error($"駐車場 \"{ele}\"");
                }

                throw new SpotNameNotMatchException(error_list);
            }


            return result_list;
        }

        public override List<QRCSVData> GetQRCSVDataList() {


            var result_list = new List<QRCSVData>();

            var list = GetFileContents(filename_qr);

            bool failed_flg = false;
            var failed_parking_name_hs_table = new HashSet<String>();

            foreach (var line in list) {

                var parking_name = line[(int)QRCSVDataDaito.ColName.ParkingName];
                try {

                    result_list.Add(new QRCSVDataDaito() {
                        spot_id = GetSpotID(parking_name),
                        parking_name = parking_name,
                        developer = line[(int)QRCSVDataDaito.ColName.Developer],
                        reception_datetime = DateTime.Parse(line[(int)QRCSVDataDaito.ColName.ReceptionDatetime]),
                        company = line[(int)QRCSVDataDaito.ColName.Company],
                        amount = int.Parse(line[(int)QRCSVDataDaito.ColName.Amount]),
                        adjust_no = line[(int)QRCSVDataDaito.ColName.AdjustNo],
                        error_code = line[(int)QRCSVDataDaito.ColName.ErrorCode],
                    });
                } catch (ArgumentException) {
                    failed_parking_name_hs_table.Add(parking_name);
                    failed_flg = true;
                    continue;
                }

            }

            if (failed_flg) {

                var error_list = new List<Store.ParkingCreditCardAgenciesSpotIDError>();
                logger_.Error("失敗駐車場名");
                foreach (var ele in failed_parking_name_hs_table) {
                    error_list.Add(new Store.ParkingCreditCardAgenciesSpotIDError() {
                        creditcard_agencies_id = CreditAgenciesMap.GetID(agent_),
                        creditcard_agencies_spot_name = ele
                    });
                    logger_.Error($"駐車場 \"{ele}\"");
                }

                throw new SpotNameNotMatchException(error_list);

            }

            return result_list;
        }

        private List<String[]> GetFileContents(String filename) {
            var list = new List<String[]>();
            var dir = new DirectoryInfo(DriverFactory.GetDownloadDir());
            var config = new CSVConfig() {
                header = true,
            };
            config.remove_char.Add("\"");
            var sjis_enc = Encoding.GetEncoding("Shift-JIS");

            foreach (var file in dir.GetFiles()) {
                if (file.Name.Contains(filename)) {
                    var result = ReadCsv(file.FullName, config, sjis_enc);
                    list.AddRange(result);
                }
            }

            return list;
        }
    }
}
