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.Exceptions;

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

namespace CSVDownloader.Web {
    class ZeusController : WebController {

        private readonly String url_ = "https://linkpt.cardservice.co.jp/merchant/";

        private readonly int max_download_num_ = 20;

        private enum XpathKey {
            INPUT_LOGIN_USERNAME,
            INPUT_LOGIN_PASSWORD,
            BUTTON_CREDIT_KESSAI,
            CHECK_PARKING,
            RADIO_TARGET_SPAN,
            SELECT_TARGET_FROM_YYYY,
            SELECT_TARGET_FROM_MM,
            SELECT_TARGET_FROM_DD,
            SELECT_TARGET_TO_YYYY,
            SELECT_TARGET_TO_MM,
            SELECT_TARGET_TO_DD,
            BUTTON_DOWNLOAD_CSV,
            BUTTON_LOGOUT,
            SUBJECT,
            FRAME_MENU,
            FRAME_CONTENTS,
        };


        private static String search_form_xpath = "//*[@id='deny_double_click']";
        private IDictionary<XpathKey, string> xpath_map_ = new Dictionary<XpathKey, string>()
        {
             {XpathKey.INPUT_LOGIN_USERNAME,"//form[@name='loginForm']//input[@name='ID']" },
             {XpathKey.INPUT_LOGIN_PASSWORD,"//*[@id='password']"},
             {XpathKey.BUTTON_CREDIT_KESSAI,"//a[contains(@href,'batch_download_face')]" },
             {XpathKey.CHECK_PARKING,$"{search_form_xpath}//input[@name='bang_list']" },
             {XpathKey.RADIO_TARGET_SPAN,$"{search_form_xpath}//input[@name='date' and @value='period']" },
             {XpathKey.SELECT_TARGET_FROM_YYYY,$"{search_form_xpath}//select[@name='spfy']" },
             {XpathKey.SELECT_TARGET_FROM_MM,$"{search_form_xpath}//select[@name='spfm']" },
             {XpathKey.SELECT_TARGET_FROM_DD,$"{search_form_xpath}//select[@name='spfd']" },
             {XpathKey.SELECT_TARGET_TO_YYYY,$"{search_form_xpath}//select[@name='epfy']" },
             {XpathKey.SELECT_TARGET_TO_MM,$"{search_form_xpath}//select[@name='epfm']" },
             {XpathKey.SELECT_TARGET_TO_DD,$"{search_form_xpath}//select[@name='epfd']" },
             {XpathKey.BUTTON_DOWNLOAD_CSV,$"{search_form_xpath}//input[@type='submit']" },
             {XpathKey.BUTTON_LOGOUT,"//a[contains(@href,'logout')]" },
             {XpathKey.FRAME_MENU,"//frame[@name='MENULIST']" },
             {XpathKey.FRAME_CONTENTS,"//frame[@name='CONTENTS']" },

         };


        public ZeusController(ChromeDriver driver) : base(driver) {
            agent_ = CreditAgent.Zeus;
        }

        public override void SetParkingDic(IDictionary<String, String> dic) {

            dic_ = new Dictionary<String, String>();
            // IPコードと駐車場名を分離。プログラムではIPコードのみ利用する。
            foreach (var ele in dic) {
                if (ele.Key == "") {
                    logger_.Warn($"検索キーが空白のためスキップ {ele.Value}");
                    continue;
                }
                String parking_name = ele.Key.Split(" ")[0].Trim();
                dic_.Add(parking_name, ele.Value);
            }
        }

        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);

                // ログイン後の「端末決済データダウンロード」が表示されることを確認する。
                SwitchToFrame(xpath_map_[XpathKey.FRAME_MENU]);
                wait_.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpath_map_[XpathKey.BUTTON_CREDIT_KESSAI])));
                SwitchToFrame();

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

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

            //期間のFrom-Toを入力
            SwitchToFrame(xpath_map_[XpathKey.FRAME_CONTENTS]);
            Click(xpath_map_[XpathKey.RADIO_TARGET_SPAN]);
            Select(xpath_map_[XpathKey.SELECT_TARGET_FROM_YYYY], from.ToString("yyyy"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_FROM_MM], from.ToString("%M"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_FROM_DD], from.ToString("%d"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_TO_YYYY], to.ToString("yyyy"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_TO_MM], to.ToString("%M"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_TO_DD], to.ToString("%d"));

            // 駐車場一覧を取得
            var parking_list = driver_.FindElementsByXPath(xpath_map_[XpathKey.CHECK_PARKING]);
            var tmp_list = new List<IWebElement>();
            int count = 0;

            // 一定件数ごとにダウンロード
            foreach (var parking in parking_list) {
                tmp_list.Add(parking);

                if (!parking.Selected) {
                    parking.Click();
                }

                if (tmp_list.Count == max_download_num_) {

                    // ダウンロード処理
                    String filename = $"zeus_{count}.csv";
                    Click(xpath_map_[XpathKey.BUTTON_DOWNLOAD_CSV]);
                    WaitForDownload(filename);

                    // チェックを戻す
                    foreach (var check in tmp_list) {
                        if (check.Selected) {
                            check.Click();
                        }
                    }
                    // クリアー処理
                    count++;
                    tmp_list.Clear();
                }

            }

            if (tmp_list.Count != 0) {
                String filename = $"zeus_{count}.csv";
                Click(xpath_map_[XpathKey.BUTTON_DOWNLOAD_CSV]);
                WaitForDownload(filename);
                tmp_list.Clear();
            }

            SwitchToFrame();

            return ResultCode.OK;
        }

        public override ResultCode Logout() {


            SwitchToFrame(xpath_map_[XpathKey.FRAME_MENU]);
            Click(xpath_map_[XpathKey.BUTTON_LOGOUT]);

            return ResultCode.OK;
        }


        public override List<CreditCSVData> GetCreditCSVDataList() {

            var result_list = new List<CreditCSVData>();


            // csvファイルパスの取得
            var config = new CSVConfig() {
                header = true,
            };

            var dir = new DirectoryInfo(DriverFactory.GetDownloadDir());

            var sjis_enc = Encoding.GetEncoding("Shift-JIS");
            var list = new List<String[]>();
            foreach (var file in dir.GetFiles()) {
                var result = ReadCsv(file.FullName, config, sjis_enc);
                list.AddRange(result);
            }


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

            foreach (var line in list) {

                // 決済金額は「-」でセットされている場合があるので
                // その際は0とする。
                var parking_name = line[(int)CreditCSVDataZeus.ColName.IP];
                try {
                    int amount = 0;
                    int.TryParse(line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.Amount], out amount);

                    result_list.Add(new Store.CreditCSVData.CreditCSVDataZeus() {
                        spot_id = GetSpotID(line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.IP]),
                        use_datetime = DateTime.Parse(line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.UseDatetime]),
                        ip = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.IP],
                        device_no = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.DeviceNo],
                        receipt_no = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.ReceiptNo],
                        certificate_no = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.CertificateNo],
                        status = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.Status],
                        error_message = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.ErrorMessage],
                        amount = amount,
                        card_no = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.CardNo],
                        expiration_date = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.ExpirationDate],
                        brand = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.Brand],
                        payment_type = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.PaymentType],
                        jis_info = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.JISInfo],
                        test = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.Test],
                        order_no = line[(int)Store.CreditCSVData.CreditCSVDataZeus.ColName.OrderNo],
                    });
                } catch (ArgumentException) {
                    failed_parking_name_hs_table.Add(parking_name);
                    failed_flg = true;
                    continue;
                }


                if (failed_flg) {
                    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;
        }
    }
}
