using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using SepehrTourApiSampleClient.Availability.GetHotelPackageList.WebApi;
using SepehrTourApiSampleClient.Booking.Book.WinForms;
using SepehrTourApiSampleClient.Booking.Book.WinForms.BookCommand.Factory;
using SepehrTourApiSampleClient.BuiltinTypeExtensions;
using AvailabilityRequestModel = Sepehr.ApiGateway.Partners.Contracts.Tour.Availability.V6.GetHotelPackageList.RequestModel;
using AvailabilityResponseModel = Sepehr.ApiGateway.Partners.Contracts.Tour.Availability.V6.GetHotelPackageList.ResponseModel;
using LockRequestModel = Sepehr.ApiGateway.Partners.Contracts.Tour.Booking.V3.Lock.RequestModel;

namespace SepehrTourApiSampleClient.Availability.GetHotelPackageList.WinForms
{
    public partial class GetHotelPackageListForm : Form
    {
        private readonly MainForm _mainForm;
        private readonly AvailabilityRequestModel.Request _getFlightsRequest;

        private AvailabilityResponseModel.Response _response;

        private List<AvailabilityRequestModel.Room> _requestRoomList = new List<AvailabilityRequestModel.Room>()
        {
            new AvailabilityRequestModel.Room
            {
                AdultCount = 2,
                ChildAgeList = new List<byte>()
            }
        };

        public GetHotelPackageListForm(
            MainForm mainForm,
            AvailabilityRequestModel.Request getFlightsRequest)
        {
            _mainForm = mainForm;
            _getFlightsRequest = getFlightsRequest;
            InitializeComponent();


            dataGridView1.Visible = false;
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.Columns.Clear();
            dataGridView1.CellClick += DataGridView1_CellClick;

            var column = new DataGridViewButtonColumn();
            column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
            dataGridView1.Columns.Add(column);

            DataGridViewButtonColumn button = new DataGridViewButtonColumn();
            button.Name = "Lock";
            button.HeaderText = "Lock";
            button.Text = "Lock";
            button.UseColumnTextForButtonValue = true;
            button.Width = 60;
            button.DefaultCellStyle.Padding = new Padding(0, 50, 10, 50);
            button.DefaultCellStyle.BackColor = Color.LightGray;
            this.dataGridView1.Columns.Add(button);





            _response = GetHotelPackageListApi.Post(
                _mainForm.txtUrl.Text,
                _getFlightsRequest);

            dataGridView1.Visible = true;
            dataGridView1.DataSource = _response
                .PackageList
                .ConvertAll(x => new ViewModels.Package(x, _response.CurrencyCode));
        }

        private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            //Only paint first column and RowIndex should be >=0 to avoid rendering column header
            if (
                e.ColumnIndex != 0
                ||
                e.RowIndex < 0
                ||
                dataGridView1.DataSource == null
                )
            {
                return;
            }


            var package = ((List<ViewModels.Package>)dataGridView1.DataSource)[e.RowIndex];

            PaintCell(package, e);

            //Cancel default painting using e.Handled = true
            e.Handled = true;
        }

        private void PaintCell(ViewModels.Package package, DataGridViewCellPaintingEventArgs e)
        {
            // Erase the cell
            var backColorBrush = new SolidBrush(Color.LightGray);
            e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
            backColorBrush.Dispose();



            DrawStringVertical($"{e.RowIndex + 1}", 1, 50, e);


            DrawString("Hotel", 32, 10, e);
            DrawString(package.Hotel.Name, 80, 10, e);

            DrawString("Room type", 32, 35, e);
            DrawString(string.Join("/", package.Hotel.RoomTypeList.ConvertAll(x => GetRoomTypeTitle(x))), 120, 35, e);

            DrawString("Amenities", 32, 60, e);
            DrawString(string.Join("     ", package.Hotel.AmenityList.ConvertAll(x => $"{x.Name}  {x.Quantity} ")), 140, 60, e);

            DrawString("Departure flight", 32, 85, e);
            if (package.DepartureFlight != null)
            {
                DrawString(package.DepartureFlight.FlightNumber, 141, 85, e);
                DrawString(package.DepartureFlight.DepartureDateTime, 201, 85, e);
                DrawString(package.DepartureFlight.ShamsiDepartureDateTime, 321, 85, e);
                DrawString(package.DepartureFlight.Airline, 409, 85, e);
                DrawString($@"{package.DepartureFlight.CabinType}_{package.DepartureFlight.BookingCode}_{package.DepartureFlight.FareName}", 466, 85, e);
            }

            DrawString("Returning flight", 32, 110, e);
            if (package.ReturningFlight != null)
            {
                DrawString(package.ReturningFlight.FlightNumber, 141, 110, e);
                DrawString(package.ReturningFlight.DepartureDateTime, 201, 110, e);
                DrawString(package.ReturningFlight.ShamsiDepartureDateTime, 321, 110, e);
                DrawString(package.ReturningFlight.Airline, 409, 110, e);
                DrawString($@"{package.ReturningFlight.CabinType}_{package.ReturningFlight.BookingCode}_{package.ReturningFlight.FareName}", 466, 110, e);
            }

            DrawString("Gross price", 750, 11, Color.DimGray, e);
            DrawString($@"{package.CurrencyCode} {package.TotalGrossPrice.FormattedNumber()}", 850, 11, e);

            DrawString("Commision", 750, 29, Color.DimGray, e);
            DrawString($@"{package.CurrencyCode} {package.TotalCommission.FormattedNumber()}", 850, 29, e);

            DrawString("Hotel Net Price", 750, 47, Color.DimGray, e);
            DrawString($@"{package.CurrencyCode} {package.TotalHotelNetPrice.FormattedNumber()}", 850, 47, e);

            DrawString("Flight Net Price", 750, 65, Color.DimGray, e);
            DrawString($@"{package.CurrencyCode} {package.TotalFlightNetPrice.FormattedNumber()}", 850, 65, e);

            DrawString("Total Net Price", 750, 83, Color.DimGray, e);
            DrawString($@"{package.CurrencyCode} {package.TotalNetPrice.FormattedNumber()}", 850, 83, e);

            DrawLine(Color.Gray, e);
        }

        private static string GetRoomTypeTitle(ViewModels.Hotel.RoomType roomType)
        {
            var result = $"{roomType.Name} {roomType.BoardTypeCode}";

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

            return result;
        }

        private void DrawString(
            string text,
            float x,
            float y,
            DataGridViewCellPaintingEventArgs e)
        {
            DrawString(text, x, y, Color.Black, e, false);
        }

        private void DrawString(
            string text,
            float x,
            float y,
            Color drawColor,
            DataGridViewCellPaintingEventArgs e)
        {
            DrawString(text, x, y, drawColor, e, false);
        }

        private void DrawStringVertical(
            string text,
            float x,
            float y,
            DataGridViewCellPaintingEventArgs e)
        {
            DrawString(text, x, y, Color.Black, e, true);
        }

        private void DrawString(
            string text,
            float x,
            float y,
            Color drawColor,
            DataGridViewCellPaintingEventArgs e,
            bool drawVertical)
        {
            Graphics formGraphics = this.CreateGraphics();
            string drawString = text;
            Font drawFont = new Font("Tahoma", 9.25F);
            SolidBrush drawBrush = new SolidBrush(drawColor);
            StringFormat drawFormat = new StringFormat();

            if (drawVertical)
            {
                drawFormat.FormatFlags = StringFormatFlags.DirectionVertical;
            }


            e.Graphics.DrawString(
                drawString,
                drawFont,
                drawBrush,
                e.CellBounds.Left + x,
                e.CellBounds.Top + y,
                drawFormat);



            drawFont.Dispose();
            drawBrush.Dispose();
            formGraphics.Dispose();
        }

        private void DrawLine(
            Color drawColor,
            DataGridViewCellPaintingEventArgs e)
        {
            SolidBrush drawBrush = new SolidBrush(drawColor);

            e.Graphics.DrawLine(
                pen: new Pen(drawBrush),
                x1: e.CellBounds.X,
                y1: e.CellBounds.Y - 1,
                x2: e.CellBounds.Width,
                y2: e.CellBounds.Y - 1);

            drawBrush.Dispose();
        }

        private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex != 1)
            {
                return;
            }

            var package = ((List<ViewModels.Package>)dataGridView1.DataSource)[e.RowIndex];

            var lockRequest = new LockRequestModel.Request
            {
                Username = _mainForm.txtUsername.Text,
                Password = _mainForm.txtPassword.Text,
                CheckinDate = _getFlightsRequest.DepartureDate,
                CheckoutDate = _getFlightsRequest.ReturningDate,
                RoomList = package
                    .Hotel
                    .RoomTypeList
                    .ConvertAll(x => new LockRequestModel.Room
                    {
                        RoomTypeSepehrGlobalId = x.SepehrGlobalId,
                        BoardTypeCode = x.BoardTypeCode,
                        AdultCount = x.AdultCount,
                        ChildAgeList = x.ChildAgeList,
                    }),
                FlightTotalPayable = package.TotalFlightNetPrice,
                HotelTotalPayable = package.TotalHotelNetPrice,
            };



            var selectedDepartureFlight = package.DepartureFlight;
            if (selectedDepartureFlight != null)
            {
                lockRequest.DepartureSegment = new LockRequestModel.FlightSegment
                {
                    FlightNumber = selectedDepartureFlight.FlightNumber,
                    FlightDate = selectedDepartureFlight.DepartureDateTime,
                    OriginIataCode = selectedDepartureFlight.Origin,
                    DestinationIataCode = selectedDepartureFlight.Destination,
                    FareName = selectedDepartureFlight.FareName,
                };
            }


            var selectedReturningFlight = package.ReturningFlight;
            if (selectedReturningFlight != null)
            {
                lockRequest.ReturningSegment = new LockRequestModel.FlightSegment
                {
                    FlightNumber = selectedReturningFlight.FlightNumber,
                    FlightDate = selectedReturningFlight.DepartureDateTime,
                    OriginIataCode = selectedReturningFlight.Origin,
                    DestinationIataCode = selectedReturningFlight.Destination,
                    FareName = selectedReturningFlight.FareName,
                };
            }


            var lockResponse = Booking.Lock.WebApi.LockApi.Post(
                _mainForm.txtUrl.Text,
                lockRequest);

            var bookCommand = CommandFactory.Create(
                url: _mainForm.txtUrl.Text,
                username: _mainForm.txtUsername.Text,
                password: _mainForm.txtPassword.Text,
                selectedDepartureFlight: selectedDepartureFlight,
                departureLockId: lockResponse.DepartureFlightLockId,
                selectedReturningFlight: selectedReturningFlight,
                returningLockId: lockResponse.ReturningFlightLockId,
                flight_totalPayable: package.TotalFlightNetPrice,
                checkinDate: _getFlightsRequest.DepartureDate.ParseAsGregorianDate(),
                checkoutDate: _getFlightsRequest.ReturningDate.ParseAsGregorianDate(),
                hotel_TotalNetPrice_TaxIncluded: package.TotalHotelNetPrice,
                hotelName: package.Hotel.Name,
                roomList: package.Hotel.RoomTypeList.ConvertAll(x => new Booking.Book.WinForms.BookCommand.Hotel.Room
                {
                    AdultCount = x.AdultCount,
                    ChildAgeList = x.ChildAgeList.ConvertAll(c => c),
                    RoomTypeName = x.Name,
                    BoardTypeCode = x.BoardTypeCode,
                    ExtrabedAssignedCount = x.ExtrabedAssignedCount,
                }),
                hotelLockId: lockResponse.HotelLockId);

            var bookForm = new BookForm(bookCommand);

            bookForm.ShowDialog();
        }

        private void dataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            //https://stackoverflow.com/a/13955658/7780428
            dataGridView1.ClearSelection();
        }

        private void btnApplyFilter_Click(object sender, EventArgs e)
        {
            var packageListAsEnumerable = _response
                .PackageList
                .AsEnumerable();

            if (string.IsNullOrWhiteSpace(txtHotelGlobalId.Text) == false)
            {
                packageListAsEnumerable = packageListAsEnumerable
                    .Where(x => x.Hotel.SepehrGlobalId == Convert.ToInt32(txtHotelGlobalId.Text));
            }

            if (string.IsNullOrWhiteSpace(txtRoomTypeGlobalId.Text) == false)
            {
                packageListAsEnumerable = packageListAsEnumerable
                    .Where(x => x.Hotel.RoomTypeList.Any(rt => rt.SepehrGlobalId == Convert.ToInt32(txtRoomTypeGlobalId.Text)));
            }

            if (string.IsNullOrWhiteSpace(txtDepartureFlightNumber.Text) == false)
            {
                packageListAsEnumerable = packageListAsEnumerable
                    .Where(x => x.DepartureFlight.FlightNumber == txtDepartureFlightNumber.Text);
            }

            if (string.IsNullOrWhiteSpace(txtReturningFlightNumber.Text) == false)
            {
                packageListAsEnumerable = packageListAsEnumerable
                    .Where(x => x.ReturningFlight.FlightNumber == txtReturningFlightNumber.Text);
            }

            dataGridView1.DataSource = packageListAsEnumerable
                .Select(x => new ViewModels.Package(x, _response.CurrencyCode))
                .ToList();
        }
    }
}
