using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using Sepehr.ApiGateway.Partners.Contracts.Flight.BulkAvailability.V17.GetFlightCount.ResponseModel;
using SepehrFlightApiSampleClient.Booking.WinForms.Book;
using SepehrFlightApiSampleClient.Booking.WinForms.Book.BookCommand.Factory;
using SepehrFlightApiSampleClient.Booking.WinForms.Lock;
using SepehrFlightApiSampleClient.BulkAvailability.WebApi;
using SepehrFlightApiSampleClient.BulkAvailability.WinForms.DateRange.ViewModels;
using BulkAvailabilityApiModel = Sepehr.ApiGateway.Partners.Contracts.Flight.BulkAvailability.V17;

namespace SepehrFlightApiSampleClient.BulkAvailability.WinForms.DateRange
{
    public partial class DateRangeForm : Form
    {
        private readonly MainForm _mainForm;
        private int? _departureLockId = null;
        private int? _returningLockId = null;
        private List<BulkAvailabilityApiModel.Charter.ResponseModel.FlightSegment> _charterFlights = new List<BulkAvailabilityApiModel.Charter.ResponseModel.FlightSegment>();
        private List<BulkAvailabilityApiModel.Webservice.ResponseModel.FlightSegment> _webserviceFlights = new List<BulkAvailabilityApiModel.Webservice.ResponseModel.FlightSegment>();

        public DateRangeForm(MainForm mainForm)
        {
            _mainForm = mainForm;
            InitializeComponent();

            dplWebserviceFlightType.SelectedIndex = 0;

            //gridFlightList.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            //gridFlightClassList.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

            btnClearSelectedDepartureFlight.Visible = false;
            btnClearSelectedReturningFlight.Visible = false;
        }

        private void btnGetDifferentially_Click(object sender, EventArgs e)
        {
            try
            {
                var watch = Stopwatch.StartNew();

                ClearUiObjects();

                _charterFlights = new List<BulkAvailabilityApiModel.Charter.ResponseModel.FlightSegment>();
                _webserviceFlights = new List<BulkAvailabilityApiModel.Webservice.ResponseModel.FlightSegment>();

                var flightCount = GetFlightCount();

                GetCharterFlights(flightCount.FlightCount);

                GetWebserviceFlights(flightCount.FlightCount);


                Application.DoEvents();

                watch.Stop();

                DataBindFlightGrid();

                MessageBox.Show(
                    $@"{gridFlightList.Rows.Count} flights{Environment.NewLine}{watch.Elapsed.TotalSeconds} seconds{Environment.NewLine}Done");

            }
            finally
            {
                btnGet.Enabled = true;
            }
        }

        private Response GetFlightCount()
        {
            var getFlightCountRequest = new BulkAvailabilityApiModel.GetFlightCount.RequestModel.Request
            {
                UserName = _mainForm.txtUsername.Text,
                Password = _mainForm.txtPassword.Text,
                FetchSupplierWebserviceFlights = chkFetchSupplierWebserviceFlights.Checked,
            };
            var flightCount = GetFlightCountApi.Post(_mainForm.txtUrl.Text, getFlightCountRequest);
            return flightCount;
        }

        private void ClearUiObjects()
        {
            btnGet.Enabled = false;
            gridFlightList.DataSource = null;
            gridFlightList.Refresh();
            gridFlightClassList.DataSource = null;
            gridFlightClassList.Refresh();
        }

        private void GetCharterFlights(int flightCount)
        {
            if (!chkFetchSupplierCharterFlights.Checked) return;

            if (flightCount < 500)
            {
                var charterRequest = new BulkAvailabilityApiModel.Charter.RequestModel.Request
                {
                    UserName = _mainForm.txtUsername.Text,
                    Password = _mainForm.txtPassword.Text,
                    FromDate = DateTime.Now.ToString("yyyy-MM-dd"), //TODO: convert to local iran time
                    ToDate = DateTime.Now.AddYears(1).ToString("yyyy-MM-dd"), //TODO: convert to local iran time
                    Language = "FA",
                    FetchFlighsWithBookingPolicy = chkFetchFlighsWithBookingPolicy.Checked
                };

                var charterResponse = GetCharterFlightsApi.Post(_mainForm.txtUrl.Text, charterRequest);
                _charterFlights.AddRange(charterResponse.CharterFlightList);
            }
            else
            {
                //get 1 to 14 days flight
                var charterRequest = new BulkAvailabilityApiModel.Charter.RequestModel.Request
                {
                    UserName = _mainForm.txtUsername.Text,
                    Password = _mainForm.txtPassword.Text,
                    FromDate = DateTime.Now.ToString("yyyy-MM-dd"), //TODO: convert to local iran time
                    ToDate = DateTime.Now.AddDays(14).ToString("yyyy-MM-dd"), //TODO: convert to local iran time
                    Language = "FA",
                    FetchFlighsWithBookingPolicy = chkFetchFlighsWithBookingPolicy.Checked
                };

                var charterResponse = GetCharterFlightsApi.Post(_mainForm.txtUrl.Text, charterRequest);
                _charterFlights.AddRange(charterResponse.CharterFlightList);

                //get 15 to 1 year flight
                charterRequest = new BulkAvailabilityApiModel.Charter.RequestModel.Request
                {
                    UserName = _mainForm.txtUsername.Text,
                    Password = _mainForm.txtPassword.Text,
                    FromDate = DateTime.Now.AddDays(15).ToString("yyyy-MM-dd"), //TODO: convert to local iran time
                    ToDate = DateTime.Now.AddYears(1).ToString("yyyy-MM-dd"), //TODO: convert to local iran time
                    Language = "FA",
                    FetchFlighsWithBookingPolicy = chkFetchFlighsWithBookingPolicy.Checked
                };

                charterResponse = GetCharterFlightsApi.Post(_mainForm.txtUrl.Text, charterRequest);
                _charterFlights.AddRange(charterResponse.CharterFlightList);
            }
        }

        private void GetWebserviceFlights(int flightCount)
        {
            if (!chkFetchSupplierWebserviceFlights.Checked) return;

            if (flightCount == 0) return;

            //webservice
            var webserviceRequest = new BulkAvailabilityApiModel.Webservice.RequestModel.Request
            {
                UserName = _mainForm.txtUsername.Text,
                Password = _mainForm.txtPassword.Text,
                FlightType = GetWebserviceFlightType(),
                Language = "FA",
            };

            var webserviceResponse = GetRange1Api.Post(_mainForm.txtUrl.Text, webserviceRequest);
            _webserviceFlights.AddRange(webserviceResponse.WebserviceFlightList);

            webserviceResponse = GetRange2Api.Post(_mainForm.txtUrl.Text, webserviceRequest);
            _webserviceFlights.AddRange(webserviceResponse.WebserviceFlightList);

            webserviceResponse = GetRange3Api.Post(_mainForm.txtUrl.Text, webserviceRequest);
            _webserviceFlights.AddRange(webserviceResponse.WebserviceFlightList);

            webserviceResponse = GetRange4Api.Post(_mainForm.txtUrl.Text, webserviceRequest);
            _webserviceFlights.AddRange(webserviceResponse.WebserviceFlightList);

            webserviceResponse = GetRange5Api.Post(_mainForm.txtUrl.Text, webserviceRequest);
            _webserviceFlights.AddRange(webserviceResponse.WebserviceFlightList);
        }

        private BindingSource _bnsFlights;
        private BindingSource _bnsFlightClasses;
        private void DataBindFlightGrid()
        {
            _bnsFlights = new BindingSource();

            var charterFlightsViewModel = _charterFlights
                .Select(f => new Flight(f))
                .ToList();

            var webserviceFlightsViewModel = _webserviceFlights
                .Select(f => new Flight(f))
                .ToList();

            var allFlightsViewModel = charterFlightsViewModel.Concat(webserviceFlightsViewModel);

            if (!string.IsNullOrEmpty(txtFlightNumberFilter.Text))
            {
                allFlightsViewModel = allFlightsViewModel
                    .Where(f => f.FlightNumber.Contains(txtFlightNumberFilter.Text));
            }

            if (!string.IsNullOrEmpty(txtOriginFilter.Text))
            {
                allFlightsViewModel = allFlightsViewModel
                    .Where(f => f.Origin == txtOriginFilter.Text);
            }

            if (!string.IsNullOrEmpty(txtDestinationFilter.Text))
            {
                allFlightsViewModel = allFlightsViewModel
                    .Where(f => f.Destination == txtDestinationFilter.Text);
            }

            if (!string.IsNullOrEmpty(txtFilterShamsiFlightDate.Text))
            {
                allFlightsViewModel = allFlightsViewModel
                    .Where(f => f.ShamsiDepartureDateTime.Contains(txtFilterShamsiFlightDate.Text));
            }

            allFlightsViewModel = allFlightsViewModel
                .OrderBy(f => f.DepartureDateTime);

            _bnsFlights.DataSource = allFlightsViewModel.ToList();

            gridFlightList.DataSource = _bnsFlights;
        }

        private void gridFlightList_SelectionChanged(object sender, EventArgs e)
        {
            if (_bnsFlights.Current == null) return;

            var flightSegment = GetCurrentFlightFromGrid();

            _bnsFlightClasses = new BindingSource();
            _bnsFlightClasses.DataSource = flightSegment.Classes;
            _bnsFlightClasses.PositionChanged += _bnsFlightClasses_PositionChanged;
            FlightClassesPositionChanged();

            gridFlightClassList.DataSource = _bnsFlightClasses;

            if (flightSegment.Stop1 || flightSegment.Stop2)
            {
                btnShowStopInfo.Visible = true;
            }
            else
            {
                btnShowStopInfo.Visible = false;
            }
        }

        private void _bnsFlightClasses_PositionChanged(object sender, EventArgs e)
        {
            FlightClassesPositionChanged();
        }

        private void FlightClassesPositionChanged()
        {
            var currentFlightClass = GetCurrentFlightClassFromGrid();

            if (currentFlightClass == null) return;

            flightClassExtraInfoUserControl1.SetFlightClass(currentFlightClass);
        }

        public Flight GetCurrentFlightFromGrid()
        {
            return (Flight)_bnsFlights?.Current;
        }

        private FlightClass GetCurrentFlightClassFromGrid()
        {
            if (_bnsFlights?.Current == null) return null;

            return (FlightClass)_bnsFlightClasses?.Current;
        }

        private void txtFlightNumberFilter_TextChanged(object sender, EventArgs e)
        {
            DataBindFlightGrid();
        }

        private void txtFilterShamsiFlightDate_TextChanged(object sender, EventArgs e)
        {
            DataBindFlightGrid();
        }

        private void txtOriginFilter_TextChanged(object sender, EventArgs e)
        {
            DataBindFlightGrid();
        }

        private void txtDestinationFilter_TextChanged(object sender, EventArgs e)
        {
            DataBindFlightGrid();
        }

        private void chkFetchSupplierWebserviceFlights_CheckedChanged(object sender, EventArgs e)
        {
            dplWebserviceFlightType.Enabled = chkFetchSupplierWebserviceFlights.Checked;
        }

        private BulkAvailabilityApiModel.Webservice.RequestModel.FlightType GetWebserviceFlightType()
        {
            if (dplWebserviceFlightType.SelectedIndex == 0)
            {
                return BulkAvailabilityApiModel.Webservice.RequestModel.FlightType.AllFlights;
            }
            else if (dplWebserviceFlightType.SelectedIndex == 1)
            {
                return BulkAvailabilityApiModel.Webservice.RequestModel.FlightType.OnlyAirlineScheduleFlights;
            }
            else
            {
                return BulkAvailabilityApiModel.Webservice.RequestModel.FlightType.OnlyWebserviceCharterFlights;
            }
        }

        private void btnBook_Click(object sender, EventArgs e)
        {
            if (_selectedDepartureFlight == null)
            {
                MessageBox.Show("Please select at least one segment to book");
                return;
            }

            var bookCommand = CommandFactory.Create(
                _selectedDepartureFlight,
                _selectedDepartureFlightClass,
                _departureLockId,
                _selectedReturningFlight,
                _selectedReturningFlightClass,
                _returningLockId);

            var bookForm = new BookForm(
                _mainForm,
                bookCommand);

            bookForm.ShowDialog();
        }

        private void btnLock_Click(object sender, EventArgs e)
        {
            if (_selectedDepartureFlight == null)
            {
                MessageBox.Show("Please select at least one segment to lock");
                return;
            }

            var lockCommand = Booking.WinForms.Lock.LockCommand.Factory.CommandFactory.Create(
                _selectedDepartureFlight,
                _selectedDepartureFlightClass,
                _selectedReturningFlight,
                _selectedReturningFlightClass);

            var lockForm = new LockForm(
                _mainForm,
                lockCommand);

            lockForm.ShowDialog();

            _departureLockId = lockForm.GetDepartureLockId();
            _returningLockId = lockForm.GetReturningLockId();
        }

        private void btnShowStopInfo_Click(object sender, EventArgs e)
        {
            var flightSegment = GetCurrentFlightFromGrid();

            MessageBox.Show(flightSegment.GetStopData());
        }

        private Flight _selectedDepartureFlight;
        private FlightClass _selectedDepartureFlightClass;
        private Flight _selectedReturningFlight;
        private FlightClass _selectedReturningFlightClass;
        private void btnSelectSegmentForBook_Click(object sender, EventArgs e)
        {
            if (_selectedDepartureFlight == null)
            {
                _selectedDepartureFlight = GetCurrentFlightFromGrid();
                _selectedDepartureFlightClass = GetCurrentFlightClassFromGrid();

                if (_selectedDepartureFlight == null)
                {
                    MessageBox.Show($"There no flight to select. Maybe you need to fetch flights first.");
                    return;
                }

                lblSelectedDepartureFlight.Text = 
                    $"Selected departure: " +
                    $"{_selectedDepartureFlight.FlightNumber}    " +
                    $"{_selectedDepartureFlight.Origin}-{_selectedDepartureFlight.Destination}    " +
                    $"{_selectedDepartureFlight.DepartureDateTime}    " +
                    $"{_selectedDepartureFlightClass.FareName}";

                btnClearSelectedDepartureFlight.Visible = true;
            }
            else
            {
                _selectedReturningFlight = GetCurrentFlightFromGrid();
                _selectedReturningFlightClass = GetCurrentFlightClassFromGrid();

                lblSelectedReturningFlight.Text = 
                    $"Selected returning: " +
                    $"{_selectedReturningFlight.FlightNumber}    " +
                    $"{_selectedReturningFlight.Origin}-{_selectedReturningFlight.Destination}    " +
                    $"{_selectedReturningFlight.DepartureDateTime}    " +
                    $"{_selectedReturningFlightClass.FareName}";

                btnClearSelectedReturningFlight.Visible = true;
            }
        }

        private void btnClearSelectedDepartureFlight_Click(object sender, EventArgs e)
        {
            _selectedDepartureFlight = null;
            _selectedDepartureFlightClass = null;

            lblSelectedDepartureFlight.Text = $"Selected departure: ";
            btnClearSelectedDepartureFlight.Visible = false;
        }

        private void btnClearSelectedReturningFlight_Click(object sender, EventArgs e)
        {
            _selectedReturningFlight = null;
            _selectedReturningFlightClass = null;

            lblSelectedReturningFlight.Text = $"Selected returning: ";
            btnClearSelectedReturningFlight.Visible = false;
        }
    }
}
