using Netina.Domain.Dtos.LargDtos;
using Syncfusion.Drawing;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;
using Syncfusion.Pdf.Grid;

namespace Netina.Core.EntityServices.OrderHandlers;

public class GetOrderInvoiceCommandHandler : IRequestHandler<GetOrderInvoiceCommand, byte[]>
{
    private readonly IRepositoryWrapper _repositoryWrapper;
    private readonly IMediator _mediator;

    private readonly PdfTrueTypeFont _gridFont;
    private readonly PdfTrueTypeFont _gridBoldFont;
    private readonly PdfStringFormat _stringFormat;
    private readonly PdfTrueTypeFont _largeFont;
    private readonly PdfTrueTypeFont _mediumFont;
    private readonly PdfTrueTypeFont _smallFont;
    private readonly PdfGridLayoutFormat _gridLayoutFormat;
    private readonly PdfGridCellStyle _cellStyle;
    private readonly PdfGridStyle _gridStyle;

    public GetOrderInvoiceCommandHandler(IRepositoryWrapper repositoryWrapper,IMediator mediator)
    {
        _repositoryWrapper = repositoryWrapper;
        _mediator = mediator;


        var path = Directory.GetCurrentDirectory();
        var settingsPath = Path.Combine(path, "wwwroot", "fonts", "iranyekanwebmediumfanum.ttf");
        MemoryStream stream = new MemoryStream(File.ReadAllBytes(settingsPath));

        _gridFont = new PdfTrueTypeFont(stream, 10, PdfFontStyle.Regular);
        _gridBoldFont = new PdfTrueTypeFont(stream, 12, PdfFontStyle.Bold);
        _stringFormat = new PdfStringFormat(PdfTextAlignment.Center, PdfVerticalAlignment.Middle);

        _largeFont = new PdfTrueTypeFont(stream, 18);
        _mediumFont = new PdfTrueTypeFont(stream, 12);
        _smallFont = new PdfTrueTypeFont(stream, 10);

        _gridLayoutFormat = new PdfGridLayoutFormat
        {
            Layout = PdfLayoutType.Paginate
        };

        _cellStyle = new PdfGridCellStyle
        {
            Font = _gridFont,
            Borders =
            {
                All = PdfPens.Transparent
            }
        };

        _gridStyle = new PdfGridStyle
        {
            CellPadding = new PdfPaddings(5, 5, 5, 5)
        };
    }
    public async Task<byte[]> Handle(GetOrderInvoiceCommand request, CancellationToken cancellationToken)
    {
        var orderLDto = await _mediator.Send(new GetOrderLDtoQuery(request.OrderId), cancellationToken);
        PdfDocument document = new PdfDocument();
        PdfPage currentPage = document.Pages.Add();
        SizeF clientSize = currentPage.Size;

        var result = HeaderAndAddress(orderLDto, currentPage, clientSize);

        //Product Table
        result = ProductTable(orderLDto, result, currentPage, clientSize);


        //Cost Table
        result = CostTable(orderLDto, result, currentPage, clientSize);

        //Dtail Table
        result = DetailTable(orderLDto, result, currentPage, clientSize);

        MemoryStream stream = new MemoryStream();
        document.Save(stream);
        document.Close(true);
        stream.Position = 0;
        return stream.ToArray();
    }

    private PdfLayoutResult HeaderAndAddress(OrderLDto order, PdfPage currentPage, SizeF clientSize)
    {
        PdfStringFormat format = new PdfStringFormat();
        format.TextDirection = PdfTextDirection.RightToLeft;
        format.Alignment = PdfTextAlignment.Right;


        var headerText = new PdfTextElement($"فاکتور فروش {order.FactorCode}", _largeFont);
        headerText.StringFormat = format;
        var result = headerText.Draw(currentPage, new PointF(clientSize.Width - 100, 5));

        var orderAtText = new PdfTextElement($"سفارش در : {order.OrderAt.ToPersianDateTime().ToLongDateString()} | {order.OrderAt:T}", _mediumFont);
        orderAtText.StringFormat = format;
        result = orderAtText.Draw(currentPage, new PointF(clientSize.Width - 100, result.Bounds.Y + 30));

        var nameText = new PdfTextElement($"{order.CustomerFullName}", _mediumFont);
        nameText.StringFormat = format;
        result = nameText.Draw(currentPage, new PointF(clientSize.Width - 100, result.Bounds.Bottom));

        var phoneText = new PdfTextElement($"{order.CustomerPhoneNumber}", _mediumFont);
        phoneText.StringFormat = new PdfStringFormat(PdfTextAlignment.Left);
        result = phoneText.Draw(currentPage, new PointF(0, result.Bounds.Y));

        PdfPen pen = new PdfPen(PdfBrushes.Black, 1f);
        PointF point1 = new PointF(0, result.Bounds.Bottom + 25);
        PointF point2 = new PointF(clientSize.Width, result.Bounds.Bottom + 25);
        currentPage.Graphics.DrawLine(pen, point1, point2);

        var addressText = new PdfTextElement($"آدرس : {order.OrderDelivery.Address}", _mediumFont);
        addressText.StringFormat = format;
        result = addressText.Draw(currentPage, new PointF(clientSize.Width - 100, result.Bounds.Y + 55));

        var postalCode = new PdfTextElement($"استان : {order.OrderDelivery.Province} | شهر : {order.OrderDelivery.City} | کد پستی : {order.OrderDelivery.PostalCode} | پلاک : {order.OrderDelivery.Plaque}", _smallFont);
        postalCode.StringFormat = format;
        result = postalCode.Draw(currentPage, new PointF(clientSize.Width - 100, result.Bounds.Bottom + 5));

        var shippingMethod = new PdfTextElement($"روش ارسال : {order.OrderDelivery.ShippingMethod} ", _mediumFont);
        shippingMethod.StringFormat = format;
        result = shippingMethod.Draw(currentPage, new PointF(clientSize.Width - 100, result.Bounds.Bottom + 5));

        PointF pointB1 = new PointF(0, result.Bounds.Bottom + 15);
        PointF pointB2 = new PointF(clientSize.Width, result.Bounds.Bottom + 15);
        currentPage.Graphics.DrawLine(pen, pointB1, pointB2);
        return result;
    }

    private PdfLayoutResult DetailTable(OrderLDto order, PdfLayoutResult result, PdfPage currentPage, SizeF clientSize)
    {
        PdfGrid detailGrid = new PdfGrid();
        detailGrid.Style.Font = _gridFont;
        detailGrid.Columns.Add(1);
        detailGrid.Columns[0].Width = 150;


        PdfGridCellStyle detailCellStyle = new PdfGridCellStyle();
        detailCellStyle.Font = _gridBoldFont;
        detailCellStyle.Borders.All = PdfPens.Transparent;
        detailCellStyle.TextBrush = PdfBrushes.White;
        detailCellStyle.BackgroundBrush = new PdfSolidBrush(new PdfColor(Color.Black));

        foreach (var payment in order.Payments.Where(p=>p.Status==PaymentStatus.Paid))
        {
            PdfGridRow paymentType = detailGrid.Rows.Add();
            paymentType.Cells[0].Value = $"{payment.Amount:N0} ریال به صورت {payment.Type.ToDisplay()} پرداخت شده";
            paymentType.Cells[0].StringFormat = _stringFormat;
            paymentType.Cells[0].Style = _cellStyle;
        }
        PdfGridRow isPaid = detailGrid.Rows.Add();
        isPaid.Cells[0].Value = order.IsPayed ? "پرداخت شده" : "پرداخت نشده";
        isPaid.Cells[0].StringFormat = _stringFormat;
        isPaid.Cells[0].Style = detailCellStyle;

        detailGrid.ApplyBuiltinStyle(PdfGridBuiltinStyle.GridTable1Light);
        detailGrid.Style = _gridStyle;

        result = detailGrid.Draw(currentPage, 0, result.Bounds.Top, 150, _gridLayoutFormat);
        return result;
    }

    private PdfLayoutResult CostTable(OrderLDto order, PdfLayoutResult result, PdfPage currentPage, SizeF clientSize)
    {
        PdfGrid pricesGrid = new PdfGrid();
        pricesGrid.Style.Font = _gridFont;
        pricesGrid.Columns.Add(2);
        pricesGrid.Columns[0].Width = 150;
        pricesGrid.Columns[1].Width = 200;

        PdfGridRow totalProductPriceRow = pricesGrid.Rows.Add();
        totalProductPriceRow.Cells[1].Value = $"قیمت تمام شده محصولات";
        totalProductPriceRow.Cells[1].StringFormat = _stringFormat;
        totalProductPriceRow.Cells[1].Style = _cellStyle;

        totalProductPriceRow.Cells[0].Value = $"{order.TotalProductsPrice:N0} ریال";
        totalProductPriceRow.Cells[0].StringFormat = _stringFormat;
        totalProductPriceRow.Cells[0].Style = _cellStyle;

        PdfGridRow totalDeliveryPrice = pricesGrid.Rows.Add();
        totalDeliveryPrice.Cells[1].Value = $"قیمت ارسال";
        totalDeliveryPrice.Cells[1].StringFormat = _stringFormat;
        totalDeliveryPrice.Cells[1].Style = _cellStyle;

        totalDeliveryPrice.Cells[0].Value = $"{order.DeliveryPrice:N0} ریال";
        totalDeliveryPrice.Cells[0].StringFormat = _stringFormat;
        totalDeliveryPrice.Cells[0].Style = _cellStyle;

        PdfGridRow discountPrice = pricesGrid.Rows.Add();
        discountPrice.Cells[1].Value = $"تخفیف";
        discountPrice.Cells[1].StringFormat = _stringFormat;
        discountPrice.Cells[1].Style = _cellStyle;

        discountPrice.Cells[0].Value = $"{order.DiscountPrice:N0} ریال";
        discountPrice.Cells[0].StringFormat = _stringFormat;
        discountPrice.Cells[0].Style = _cellStyle;

        PdfGridRow taxesPrice = pricesGrid.Rows.Add();
        taxesPrice.Cells[1].Value = $"مالیاتــــ";
        taxesPrice.Cells[1].StringFormat = _stringFormat;
        taxesPrice.Cells[1].Style = _cellStyle;

        taxesPrice.Cells[0].Value = $"{order.TaxesPrice:N0} ریال";
        taxesPrice.Cells[0].StringFormat = _stringFormat;
        taxesPrice.Cells[0].Style = _cellStyle;



        PdfGridRow totalPrice = pricesGrid.Rows.Add();
        totalPrice.Cells[1].Value = $"مبلغ پرداختی";
        totalPrice.Cells[1].StringFormat = _stringFormat;
        totalPrice.Cells[1].Style = _cellStyle;

        totalPrice.Cells[0].Value = $"{order.TotalPrice:N0} ریال";
        totalPrice.Cells[0].StringFormat = _stringFormat;
        totalPrice.Cells[0].Style = _cellStyle;

        pricesGrid.ApplyBuiltinStyle(PdfGridBuiltinStyle.GridTable1Light);
        pricesGrid.Style = _gridStyle;
        result = pricesGrid.Draw(currentPage, clientSize.Width - 430, result.Bounds.Bottom + 15, 350, _gridLayoutFormat);
        return result;
    }

    private PdfLayoutResult ProductTable(OrderLDto order , PdfLayoutResult result , PdfPage currentPage ,SizeF clientSize )
    {

        PdfGrid grid = new PdfGrid();
        grid.Style.Font = _gridFont;
        grid.Columns.Add(4);
        grid.Columns[0].Width = 100;
        grid.Columns[1].Width = 100;
        grid.Columns[2].Width = 50;

        grid.Headers.Add(1);
        _stringFormat.TextDirection = PdfTextDirection.RightToLeft;
        _stringFormat.WordWrap = PdfWordWrapType.Word;

        PdfGridRow header = grid.Headers[0];
        header.Cells[3].Value = "محصولات";
        header.Cells[3].Style.Font = _gridBoldFont;
        header.Cells[3].StringFormat = _stringFormat;

        header.Cells[2].Value = "تعداد";
        header.Cells[2].Style.Font = _gridBoldFont;
        header.Cells[2].StringFormat = _stringFormat;

        header.Cells[1].Value = "قیمت فی";
        header.Cells[1].Style.Font = _gridBoldFont;
        header.Cells[1].StringFormat = _stringFormat;

        header.Cells[0].Value = "قیمت کل";
        header.Cells[0].Style.Font = _gridBoldFont;
        header.Cells[0].StringFormat = _stringFormat;

        PdfGridCellStyle headerCellStyle = new PdfGridCellStyle();
        headerCellStyle.Font = _gridFont;

        headerCellStyle.Borders.All = PdfPens.Transparent;
        headerCellStyle.TextBrush = PdfBrushes.White;
        headerCellStyle.BackgroundBrush = new PdfSolidBrush(new PdfColor(Color.Black));

        for (int i = 0; i < header.Cells.Count; i++)
        {
            PdfGridCell cell = header.Cells[i];
            cell.Style = headerCellStyle;
        }


        foreach (var orderProduct in order.OrderProducts)
        {
            PdfGridRow row = grid.Rows.Add();
            row.Cells[3].Value = orderProduct.ProductName;
            row.Cells[3].StringFormat = _stringFormat;
            row.Cells[3].Style = _cellStyle;

            row.Cells[2].Value = orderProduct.Count.ToString();
            row.Cells[2].StringFormat = _stringFormat;
            row.Cells[2].Style = _cellStyle;

            row.Cells[1].Value = $"{orderProduct.ProductFeeWithDiscount:N0} ریال";
            row.Cells[1].StringFormat = _stringFormat;
            row.Cells[1].Style = _cellStyle;

            row.Cells[0].Value = $"{orderProduct.ProductCost:N0} ریال";
            row.Cells[0].StringFormat = _stringFormat;
            row.Cells[0].Style = _cellStyle;
        }

        grid.Style = _gridStyle;
        grid.ApplyBuiltinStyle(PdfGridBuiltinStyle.GridTable1Light);
        result = grid.Draw(currentPage, 0, result.Bounds.Bottom + 25, clientSize.Width, _gridLayoutFormat);
        return result;
    }
}