using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using SepehrFlightApiSampleClient.Booking.WebApi;
using SepehrFlightApiSampleClient.Booking.WinForms.Book.InMemoryDatabase.BookedPnrs.Repository;
using SepehrFlightApiSampleClient.Booking.WinForms.Book.InMemoryDatabase.FailedRequests.Model;
using SepehrFlightApiSampleClient.Booking.WinForms.Book.InMemoryDatabase.FailedRequests.Repository;
using SepehrFlightApiSampleClient.Booking.WinForms.Book.PassengerUserControls;
using SepehrFlightApiSampleClient.BuiltinTypeExtensions;
using BookRequestModel = Sepehr.ApiGateway.Partners.Contracts.Flight.Booking.V12.Book.RequestModel;

namespace SepehrFlightApiSampleClient.Booking.WinForms.Book
{
    public partial class BookForm : Form
    {
        private readonly MainForm _mainForm;
        private readonly BookCommand.Command _command;

        public BookForm(
            MainForm mainForm,
            BookCommand.Command command)
        {
            _mainForm = mainForm;
            _command = command;
            InitializeComponent();

            SyncSelectedFlight();

            CalculateTotalPayable();
        }

        private void SyncSelectedFlight()
        {
            txtBookYourLocalInventoryPnr.Text = Guid.NewGuid().ToString();

            txtDepartureFlightNumber.Text = _command.Departure.FlightNumber;
            dtpDepartureFlightDate.Value = _command.Departure.DepartureDateTime.ParseFlightDate();
            txtDepartureOrigin.Text = _command.Departure.OriginIataCode;
            txtDepartureDestination.Text = _command.Departure.DestinationIataCode;
            txtDepartureFareName.Text = _command.Departure.FareName;
            txtDepartureLockId.Text = _command.Departure.LockId?.ToString();

            if (_command.Returning != null)
            {
                txtReturningFlightNumber.Text = _command.Returning.FlightNumber;
                dtpReturningFlightDate.Value = _command.Returning.DepartureDateTime.ParseFlightDate();
                txtReturningOrigin.Text = _command.Returning.OriginIataCode;
                txtReturningDestination.Text = _command.Returning.DestinationIataCode;
                txtReturningFareName.Text = _command.Returning.FareName;
                txtReturningLockId.Text = _command.Returning.LockId?.ToString();
            }
            else
            {
                txtReturningFlightNumber.Visible = false;
                dtpReturningFlightDate.Visible = false;
                txtReturningOrigin.Visible = false;
                txtReturningDestination.Visible = false;
                txtReturningFareName.Visible = false;
                txtReturningLockId.Visible = false;
            }


            passengersPanel.Controls.Clear();
            var adultUserControl = new AdultUserControl(
                GetSingleAdultPayable(),
                isInternationalRoute: RouteService.IsInternationalRoute(
                    _command.Departure.OriginIataCode,
                    _command.Departure.DestinationIataCode),
                passengersPanel: passengersPanel,
                calculateTotalPayableFunction: CalculateTotalPayable);
            adultUserControl.Dock = DockStyle.Top;
            passengersPanel.Controls.Add(adultUserControl);
        }

        private void btnBook_Click(object sender, EventArgs e)
        {
            var adultList = GetAdultList();
            var childList = GetChildList();
            var infantList = GetInfantList();

            var request = new BookRequestModel.Request
            {
                UserName = _mainForm.txtUsername.Text,
                Password = _mainForm.txtPassword.Text,
                AdultPassengerList = adultList,
                ChildPassengerList = childList,
                InfantPassengerList = infantList,
                MobileNumber = txtBookMobileNumber.Text,
                Email = txtBookEmail.Text,
                YourLocalInventoryPnr = txtBookYourLocalInventoryPnr.Text,
                TotalPayable = decimal.Parse(txtTotalPayable.Text, CultureInfo.InvariantCulture),
                Remarks = txtRemarks.Text,
            };

            if (
                _command.Departure != null
                &&
                _command.Returning != null)
            {
                request.DepartureSegment = new BookRequestModel.FlightSegment
                {
                    OriginIataCode = txtDepartureOrigin.Text,
                    DestinationIataCode = txtDepartureDestination.Text,
                    DepartureDateTime = dtpDepartureFlightDate.Value.ToString("yyyy-MM-dd HH:mm"),
                    FlightNumber = txtDepartureFlightNumber.Text,
                    FareName = txtDepartureFareName.Text,
                    LockId = string.IsNullOrEmpty(txtDepartureLockId.Text)
                        ? (int?)null
                        : Convert.ToInt32(txtDepartureLockId.Text)
                };

                request.ReturningSegment = new BookRequestModel.FlightSegment
                {
                    OriginIataCode = txtReturningOrigin.Text,
                    DestinationIataCode = txtReturningDestination.Text,
                    DepartureDateTime = dtpReturningFlightDate.Value.ToString("yyyy-MM-dd HH:mm"),
                    FlightNumber = txtReturningFlightNumber.Text,
                    FareName = txtReturningFareName.Text,
                    LockId = string.IsNullOrEmpty(txtReturningLockId.Text)
                        ? (int?)null
                        : Convert.ToInt32(txtReturningLockId.Text)
                };
            }
            else
            {
                request.DepartureSegment = new BookRequestModel.FlightSegment
                {
                    OriginIataCode = txtDepartureOrigin.Text,
                    DestinationIataCode = txtDepartureDestination.Text,
                    DepartureDateTime = dtpDepartureFlightDate.Value.ToString("yyyy-MM-dd HH:mm"),
                    FlightNumber = txtDepartureFlightNumber.Text,
                    FareName = txtDepartureFareName.Text,
                    LockId = string.IsNullOrEmpty(txtDepartureLockId.Text)
                        ? (int?)null
                        : Convert.ToInt32(txtDepartureLockId.Text)
                };
            }

            try
            {
                var response = BookApi.Post(_mainForm.txtUrl.Text, request);

                var repositoryModel = ApiResponseModelToRepositoryModelConvertor.Convert(
                    response,
                    txtBookYourLocalInventoryPnr.Text);
                BookedPnrRepository.Add(repositoryModel);

                var bookResponseForm = new BookResponseForm();
                bookResponseForm.txtResponse.Text = response.SerializeToJsonWithFormatIndented();
                bookResponseForm.Show();
            }
            catch
            {
                FailedRequestRepository.Add(new FailedRequest
                {
                    Pnr = txtBookYourLocalInventoryPnr.Text,
                });
                throw;
            }

        }

        private List<BookRequestModel.Passenger> GetAdultList()
        {
            var adultList = new List<BookRequestModel.Passenger>();
            foreach (Control passengerUserControl in passengersPanel.Controls)
            {
                var adultUserControl = passengerUserControl as AdultUserControl;
                if (adultUserControl != null)
                {
                    adultList.Add(adultUserControl.GetPassengerInfo());
                }
            }

            return adultList;
        }

        private List<BookRequestModel.Passenger> GetChildList()
        {
            var childList = new List<BookRequestModel.Passenger>();
            foreach (Control passengerUserControl in passengersPanel.Controls)
            {
                var childUserControl = passengerUserControl as ChildUserControl;
                if (childUserControl != null)
                {
                    childList.Add(childUserControl.GetPassengerInfo());
                }
            }

            return childList;
        }

        private List<BookRequestModel.Passenger> GetInfantList()
        {
            var infantList = new List<BookRequestModel.Passenger>();
            foreach (Control passengerUserControl in passengersPanel.Controls)
            {
                var infantUserControl = passengerUserControl as InfantUserControl;
                if (infantUserControl != null)
                {
                    infantList.Add(infantUserControl.GetPassengerInfo());
                }
            }

            return infantList;
        }

        private void CalculateTotalPayable()
        {
            int adultCount = GetAdultList().Count;
            int childCount = GetChildList().Count;
            int infantCount = GetInfantList().Count;
            decimal totalPayable;

            if (
                _command.Departure != null
                &&
                _command.Returning != null)
            {
                totalPayable =
                    _command.Departure.AdultPayable * adultCount
                    +
                    _command.Departure.ChildPayable * childCount
                    +
                    _command.Departure.InfantPayable * infantCount
                    +
                    _command.Returning.AdultPayable * adultCount
                    +
                    _command.Returning.ChildPayable * childCount
                    +
                    _command.Returning.InfantPayable * infantCount;
            }
            else
            {
                totalPayable =
                    _command.Departure.AdultPayable * adultCount
                    +
                    _command.Departure.ChildPayable * childCount
                    +
                    _command.Departure.InfantPayable * infantCount;
            }

            txtTotalPayable.Text = totalPayable.FormattedNumber();
        }

        private void btnAddAdult_Click(object sender, EventArgs e)
        {
            var adultUserControl = new AdultUserControl(
                GetSingleAdultPayable(),
                isInternationalRoute: RouteService.IsInternationalRoute(
                    _command.Departure.OriginIataCode,
                    _command.Departure.DestinationIataCode),
                passengersPanel: passengersPanel,
                calculateTotalPayableFunction: CalculateTotalPayable);
            adultUserControl.Dock = DockStyle.Top;
            passengersPanel.Controls.Add(adultUserControl);

            CalculateTotalPayable();
        }

        private void btnAddChild_Click(object sender, EventArgs e)
        {
            var childUserControl = new ChildUserControl(
                GetSingleChildPayable(),
                isInternationalRoute: RouteService.IsInternationalRoute(
                    _command.Departure.OriginIataCode,
                    _command.Departure.DestinationIataCode),
                passengersPanel: passengersPanel,
                calculateTotalPayableFunction: CalculateTotalPayable);
            childUserControl.Dock = DockStyle.Bottom;
            passengersPanel.Controls.Add(childUserControl);

            CalculateTotalPayable();
        }

        private void btnAddInfant_Click(object sender, EventArgs e)
        {
            var infantUserControl = new InfantUserControl(
                GetSingleInfantPayable(),
                isInternationalRoute: RouteService.IsInternationalRoute(
                    _command.Departure.OriginIataCode,
                    _command.Departure.DestinationIataCode),
                passengersPanel: passengersPanel,
                calculateTotalPayableFunction: CalculateTotalPayable);
            infantUserControl.Dock = DockStyle.Bottom;
            passengersPanel.Controls.Add(infantUserControl);

            CalculateTotalPayable();
        }

        private decimal GetSingleAdultPayable()
        {
            if (
                _command.Departure != null
                &&
                _command.Returning != null)
            {
                return
                    _command.Departure.AdultPayable
                    +
                    _command.Returning.AdultPayable;
            }
            else
            {
                return _command.Departure.AdultPayable;
            }
        }

        private decimal GetSingleChildPayable()
        {
            if (
                _command.Departure != null
                &&
                _command.Returning != null)
            {
                return
                    _command.Departure.ChildPayable
                    +
                    _command.Returning.ChildPayable;
            }
            else
            {
                return _command.Departure.ChildPayable;
            }
        }

        private decimal GetSingleInfantPayable()
        {
            if (
                _command.Departure != null
                &&
                _command.Returning != null)
            {
                return
                    _command.Departure.InfantPayable
                    +
                    _command.Returning.InfantPayable;
            }
            else
            {
                return _command.Departure.InfantPayable;
            }
        }
    }
}
