using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Forms;
using SepehrTourApiSampleClient.Booking.Book.WebApi;
using SepehrTourApiSampleClient.Booking.Book.WinForms.BookCommand.Hotel;
using SepehrTourApiSampleClient.Booking.Book.WinForms.InMemoryDatabase.BookedPnrs.Repository;
using SepehrTourApiSampleClient.Booking.Book.WinForms.InMemoryDatabase.FailedRequests.Model;
using SepehrTourApiSampleClient.Booking.Book.WinForms.InMemoryDatabase.FailedRequests.Repository;
using SepehrTourApiSampleClient.Booking.Book.WinForms.PassengerUserControls;
using SepehrTourApiSampleClient.BuiltinTypeExtensions;
using BookRequestModel = Sepehr.ApiGateway.Partners.Contracts.Tour.Booking.V3.Book.RequestModel;
// ReSharper disable InconsistentNaming

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

        public BookForm(BookCommand.Command command)
        {
            _command = command;

            InitializeComponent();

            SyncSelectedFlight();
            SyncSelectedHotel();
        }

        private void SyncSelectedFlight()
        {
            if (_command.DepartureFlight != null)
            {
                txtDepartureFlightNumber.Text = _command.DepartureFlight.FlightNumber;
                dtpDepartureFlightDate.Value = _command.DepartureFlight.DepartureDateTime.ParseFlightDate();
                txtDepartureOrigin.Text = _command.DepartureFlight.OriginIataCode;
                txtDepartureDestination.Text = _command.DepartureFlight.DestinationIataCode;
                txtDepartureFareName.Text = _command.DepartureFlight.FareName;
                txtDepartureLockId.Text = _command.DepartureFlight.LockId?.ToString(CultureInfo.InvariantCulture);
            }
            else
            {
                txtDepartureFlightNumber.Visible = false;
                dtpDepartureFlightDate.Visible = false;
                txtDepartureOrigin.Visible = false;
                txtDepartureDestination.Visible = false;
                txtDepartureFareName.Visible = false;
                txtDepartureLockId.Visible = false;
            }
            

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

            txtFlightTotalPayable.Text = _command.FlightTotalPayable.ToString(CultureInfo.InvariantCulture);
        }

        private void SyncSelectedHotel()
        {
            txtBookYourLocalInventoryPnr.Text = Guid.NewGuid().ToString();
            txtHotelTotalPayable.Text = _command.Hotel.TotalNetPrice_TaxIncluded.ToString(CultureInfo.InvariantCulture);
            lblHotelName.Text = _command.Hotel.HotelName;
            lblCheckin.Text = _command.Hotel.CheckinDate.ToString("yyyy-MM-dd");
            lblCheckout.Text = _command.Hotel.CheckoutDate.ToString("yyyy-MM-dd");
            txtHotelLockId.Text = _command.Hotel.LockId.ToString(CultureInfo.InvariantCulture);

            var isInternationalRoute = GetIsInternationalRoute();


            roomsPanel.Controls.Clear();

            for (var roomIndex = _command.Hotel.RoomList.Count - 1; roomIndex >= 0; roomIndex--)
            {
                var room = _command.Hotel.RoomList[roomIndex];

                var roomUserControl = new RoomUserControl();
                roomUserControl.Dock = DockStyle.Top;
                roomUserControl.lblRoomNumber.Text = GetRoomTitle(roomIndex, room);
                roomsPanel.Controls.Add(roomUserControl);

                foreach (var childAge in room.ChildAgeList)
                {
                    var childUserControl = new ChildUserControl(
                        isInternationalRoute,
                        childAge,
                        _command.Hotel.CheckinDate);
                    childUserControl.Dock = DockStyle.Top;
                    roomUserControl.passengersPanel.Controls.Add(childUserControl);
                }

                for (int counter = 0; counter < room.AdultCount; counter++)
                {
                    var adultUserControl = new AdultUserControl(
                        isInternationalRoute);
                    adultUserControl.Dock = DockStyle.Top;
                    roomUserControl.passengersPanel.Controls.Add(adultUserControl);
                }
            }
        }

        private static string GetRoomTitle(int roomIndex, Room room)
        {
            var result = $"Room {roomIndex + 1} - {room.RoomTypeName} {room.BoardTypeCode}";

            if (room.ExtrabedAssignedCount > 0)
            {
                result += $" ({room.ExtrabedAssignedCount} Extrabed)";
            }

            return result;
        }

        private bool GetIsInternationalRoute()
        {
            bool isInternationalRoute;

            if (_command.DepartureFlight != null)
            {
                isInternationalRoute = RouteService.IsInternationalRoute(
                    _command.DepartureFlight.OriginIataCode,
                    _command.DepartureFlight.DestinationIataCode);
            }
            else
            {
                isInternationalRoute = RouteService.IsInternationalRoute(
                    _command.ReturningFlight.OriginIataCode,
                    _command.ReturningFlight.DestinationIataCode);
            }

            return isInternationalRoute;
        }

        private void btnBook_Click(object sender, EventArgs e)
        {
            var request = new BookRequestModel.Request
            {
                Username = _command.Username,
                Password = _command.Password,
                HotelLockId = string.IsNullOrWhiteSpace(txtHotelLockId.Text) ? 0 : Convert.ToInt32(txtHotelLockId.Text),
                YourLocalInventoryPnr = txtBookYourLocalInventoryPnr.Text,
                MobileNumber = txtBookMobileNumber.Text,
                Email = txtBookEmail.Text,
                Remarks = string.Empty,
                DepartureSegment = GetRequestDepartureFlightSegment(_command.DepartureFlight),
                ReturningSegment = GetRequestReturningFlightSegment(_command.ReturningFlight),
                RoomList = GetRequestRoomList(),
                FlightTotalPayable = decimal.Parse(txtFlightTotalPayable.Text, CultureInfo.InvariantCulture),
                HotelTotalPayable = decimal.Parse(txtHotelTotalPayable.Text, CultureInfo.InvariantCulture),
            };


            try
            {
                var response = BookApi.Post(_command.Url, 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 BookRequestModel.FlightSegment GetRequestDepartureFlightSegment(BookCommand.Flight.FlightSegment flightSegment)
        {
            if (flightSegment == null)
            {
                return null;
            }

            return new BookRequestModel.FlightSegment
            {
                FlightNumber = txtDepartureFlightNumber.Text,
                DepartureDateTime = dtpDepartureFlightDate.Value.ToString("yyyy-MM-dd HH:mm"),
                OriginIataCode = txtDepartureOrigin.Text,
                DestinationIataCode = txtDepartureDestination.Text,
                FareName = txtDepartureFareName.Text,
                LockId = string.IsNullOrWhiteSpace(txtDepartureLockId.Text) ? (int?)null : Convert.ToInt32(txtDepartureLockId.Text),
            };
        }

        private BookRequestModel.FlightSegment GetRequestReturningFlightSegment(BookCommand.Flight.FlightSegment flightSegment)
        {
            if (flightSegment == null)
            {
                return null;
            }

            return new BookRequestModel.FlightSegment
            {
                FlightNumber = txtReturningFlightNumber.Text,
                DepartureDateTime = dtpReturningFlightDate.Value.ToString("yyyy-MM-dd HH:mm"),
                OriginIataCode = txtReturningOrigin.Text,
                DestinationIataCode = txtReturningDestination.Text,
                FareName = txtReturningFareName.Text,
                LockId = string.IsNullOrWhiteSpace(txtReturningLockId.Text) ? (int?)null : Convert.ToInt32(txtReturningLockId.Text),
            };
        }

        private List<BookRequestModel.Room> GetRequestRoomList()
        {
            var result = new List<BookRequestModel.Room>();

            for (var roomIndex = roomsPanel.Controls.Count - 1; roomIndex >= 0; roomIndex--)
            {
                var roomUserControl = (RoomUserControl)roomsPanel.Controls[roomIndex];

                var requestAdultList = new List<BookRequestModel.Guest>();
                foreach (Control passengerUserControl in roomUserControl.passengersPanel.Controls)
                {
                    var adultUserControl = passengerUserControl as AdultUserControl;
                    if (adultUserControl != null)
                    {
                        requestAdultList.Add(adultUserControl.GetGuestInfo());
                    }
                }

                var requestChildList = new List<BookRequestModel.Guest>();
                foreach (Control passengerUserControl in roomUserControl.passengersPanel.Controls)
                {
                    var childUserControl = passengerUserControl as ChildUserControl;
                    if (childUserControl != null)
                    {
                        requestChildList.Add(childUserControl.GetGuestInfo());
                    }
                }

                result.Add(new BookRequestModel.Room
                {
                    AdultGuestList = requestAdultList,
                    ChildGuestList = requestChildList,
                });
            }

            return result;
        }
    }
}
