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 HelloTechnoController : WebController {

        private readonly String url_ = "https://skysun.crepass.net/40599/hello-techno/index.php";

        private List<CreditCSVData> csv_data_list_ = new List<CreditCSVData>();

        private enum XpathKey {
            INPUT_LOGIN_USERNAME,
            INPUT_LOGIN_PASSWORD,
            BUTTON_CREDIT_KESSAI,
            RADIO_TARGET_SPAN,
            SELECT_TARGET_FROM_YYYYMM,
            SELECT_TARGET_FROM_DD,
            SELECT_TARGET_TO_YYYYMM,
            SELECT_TARGET_TO_DD,
            BUTTON_CONFIRM_CSV,
            TABLE_CSV,
            PAGER,
            BUTTON_LOGOUT,
        };

        private IDictionary<XpathKey, string> xpath_map_ = new Dictionary<XpathKey, string>()
      {
             {XpathKey.INPUT_LOGIN_USERNAME,@"//*[@id='accountId']"},
             {XpathKey.INPUT_LOGIN_PASSWORD,@"//*[@id='myPassword']"},
             {XpathKey.BUTTON_CREDIT_KESSAI,@"//*[@id='history']/a"},
             {XpathKey.RADIO_TARGET_SPAN,@"//select[@name='yyyymm_s']/preceding-sibling::input[@name='term_type']"},
             {XpathKey.SELECT_TARGET_FROM_YYYYMM,$"//select[@name='yyyymm_s']" },
             {XpathKey.SELECT_TARGET_FROM_DD,$"//select[@name='dd_s']" },
             {XpathKey.SELECT_TARGET_TO_YYYYMM,$"//select[@name='yyyymm_e']" },
             {XpathKey.SELECT_TARGET_TO_DD,$"//select[@name='dd_e']" },
             {XpathKey.BUTTON_CONFIRM_CSV,$"//*[@id='mag_top3']/table/tbody/tr/td[1]/input" },
             {XpathKey.TABLE_CSV,$"/html/body/div[1]/div[5]/table[2]" },
             {XpathKey.PAGER,$"/html/body/div[1]/div[7]/p[1]" },
             {XpathKey.BUTTON_LOGOUT,$"//*[@id='log_out']/a/img" },

         };

        public HelloTechnoController(ChromeDriver driver) : base(driver) {
            agent_ = CreditAgent.HT;
        }

        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.ElementToBeClickable(By.XPath(xpath_map_[XpathKey.BUTTON_CREDIT_KESSAI])));

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

        public override ResultCode Download(DateTime from, DateTime to) {

            csv_data_list_.Clear();

            // クレジットカード承認結果一覧画面に移行
            Click(xpath_map_[XpathKey.BUTTON_CREDIT_KESSAI]);

            // 承認処理日のFrom-Toを入力
            Select(xpath_map_[XpathKey.SELECT_TARGET_FROM_YYYYMM], from.ToString("yyyyMM"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_FROM_DD], from.ToString("dd"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_TO_YYYYMM], to.ToString("yyyyMM"));
            Select(xpath_map_[XpathKey.SELECT_TARGET_TO_DD], to.ToString("dd"));

            // 各種ラジオチェックを入力
            Click(xpath_map_[XpathKey.RADIO_TARGET_SPAN]);


            // 条件確定
            Click(xpath_map_[XpathKey.BUTTON_CONFIRM_CSV]);

            GetAllData();

            return ResultCode.OK;
        }

        public override ResultCode Logout() {

            try {
                Click(xpath_map_[XpathKey.BUTTON_LOGOUT]);

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

            return ResultCode.OK;
        }


        public override List<CreditCSVData> GetCreditCSVDataList() {

            return csv_data_list_;
        }

        private void GetAllData() {

            int page = 1;

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

            while (true) {


                // TABLEからデータを取得する。
                var table = wait_.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath_map_[XpathKey.TABLE_CSV])));

                var tag_tr = table.FindElements(By.TagName("tr"));



                // ヘッダー行はスキップしたうえで進める。
                for (var i = 1; i < tag_tr.Count; i++) {
                    var tag_td = tag_tr[i].FindElements(By.TagName("td"));
                    if (tag_td.Count != 999) {
                        //throw new Exception("想定外の行構成");
                    }


                    var parking_name = tag_td[(int)CreditCSVDataHelloTechno.ColName.ParkingCode].Text;
                    try {
                        var data = new CreditCSVDataHelloTechno() {
                            spot_id = GetSpotID(parking_name),
                            register_datetime = DateTime.Parse(tag_td[(int)CreditCSVDataHelloTechno.ColName.RegisterDatetime].Text),
                            user_code = tag_td[(int)CreditCSVDataHelloTechno.ColName.UserCode].Text,
                            parking_code = parking_name,
                            device_no = tag_td[(int)CreditCSVDataHelloTechno.ColName.DeviceNo].Text,
                            adjust_no = tag_td[(int)CreditCSVDataHelloTechno.ColName.AdjustNo].Text,
                            trade = tag_td[(int)CreditCSVDataHelloTechno.ColName.Trade].Text,
                            amount = int.Parse(tag_td[(int)CreditCSVDataHelloTechno.ColName.Amount].Text.Replace(",", "")),
                            card_company_name = tag_td[(int)CreditCSVDataHelloTechno.ColName.CardCompanyName].Text,
                            approval_no = tag_td[(int)CreditCSVDataHelloTechno.ColName.ApprovalNo].Text,
                            response_no = tag_td[(int)CreditCSVDataHelloTechno.ColName.ResponseNo].Text,
                            error = tag_td[(int)CreditCSVDataHelloTechno.ColName.Error].Text,
                        };

                        var cancel_date = tag_td[(int)CreditCSVDataHelloTechno.ColName.CancelDate].Text;
                        if (cancel_date.Length != 0) {
                            data.cancel_date = DateTime.Parse(cancel_date);
                        }

                        // リストに挿入する。
                        csv_data_list_.Add(data);
                    } catch (ArgumentException) {
                        failed_parking_name_hs_table.Add(parking_name);
                        failed_flg = true;
                        continue;
                    }


                }

                // ページ操作
                // 戻ると進むのボタンの組み合わせで操作を行う。
                var pager = driver_.FindElementByXPath(xpath_map_[XpathKey.PAGER]);
                var tag_a = pager.FindElements(By.TagName("a"));
                if (page == 1 && tag_a.Count == 1) {
                    // 最初のページで次のボタン
                    Click(tag_a[0]);
                    page++;
                } else if (page != 1 && tag_a.Count == 2) {
                    // 戻ると進むのボタンを検出
                    Click(tag_a[1]);
                    page++;
                } else if (page != 1 && tag_a.Count == 1) {
                    // 最終ページを検出
                    break;
                } else if (page == 1 && tag_a.Count == 0) {
                    // 1ページのみ
                    break;
                } else {
                    // 想定外のパターン
                    throw new Exception("ページング不正検出");
                }

            }



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

            }

        }

    }
}
