using Application.Abstractions.Data;
using Domain.Entities.Common.ValueObject;
using Domain.Entities.Payments.Danal;
using Domain.Entities.Payments.Danal.ValueObject;
using Microsoft.EntityFrameworkCore;
using SharedKernel.Extensions;

namespace Web.Api.Endpoints.Payment;

/// <summary>가상계좌 입금 통보 (다날 서버→서버)</summary>
internal sealed class VirtualAccountNoti : IEndpoint
{
    public void MapEndpoint(IEndpointRouteBuilder app)
    {
        /// 다날 NotiUrl 콜백 (IP: 150.242.132.116). 입금 확인 → 포인트 적립
        app.MapPost("api/payment/noti/vaccount", async (
            HttpContext httpContext,
            IAppDbContext db,
            CancellationToken ct
        ) => {

            // IP 검증
            var clientIP = httpContext.GetClientIP();

            // 요청 파싱
            var body = await httpContext.Request.ReadFromJsonAsync<VAccountNotiBody>(ct);
            if (body is null)
            {
                return Results.Json(new { code = "FAIL" }, statusCode: 400);
            }

            // 주문 조회
            var order = await db.PaymentOrder.FirstOrDefaultAsync(o => o.OrderID == body.OrderID, ct);
            if (order is null)
            {
                return Results.Json(new { code = "FAIL" });
            }

            // 중복 입금 방지
            if (order.Status == Domain.Entities.Payments.ValueObject.PaymentStatus.Paid)
            {
                return Results.Json(new { code = "SUCCESS" });
            }

            // 금액 확인
            if (!int.TryParse(body.Amount, out var amount) || amount != order.Amount)
            {
                await db.DanalLog.AddAsync(DanalLog.Create(
                    order.MemberID, DanalLogType.Failed,
                    "AMOUNT_MISMATCH", $"금액 불일치: 요청={body.Amount}, 주문={order.Amount}",
                    body.TransactionID, body.OrderID), ct);
                await db.SaveChangesAsync(ct);
                return Results.Json(new { code = "FAIL" });
            }

            // 결제 완료 처리
            order.MarkPaid(body.TransactionID ?? "");

            // 지갑 포인트 충전
            var wallet = await db.Wallet.FirstOrDefaultAsync(w => w.MemberID == order.MemberID, ct);
            if (wallet is null)
            {
                await db.DanalLog.AddAsync(DanalLog.Create(
                    order.MemberID, DanalLogType.Error,
                    "WALLET_NOT_FOUND", "지갑 정보를 찾을 수 없습니다.",
                    body.TransactionID, body.OrderID), ct);
                await db.SaveChangesAsync(ct);
                return Results.Json(new { code = "FAIL" });
            }

            wallet.CreditPgCharge(
                Money.KRW(order.PointAmount),
                "가상계좌 입금 완료",
                order.OrderID
            );

            await db.DanalLog.AddAsync(DanalLog.Create(
                order.MemberID, DanalLogType.Webhook,
                "SUCCESS", "가상계좌 입금 완료",
                body.TransactionID, body.OrderID), ct);

            await db.SaveChangesAsync(ct);

            return Results.Json(new { code = "SUCCESS" });
        })
        .WithTags("Payment")
        .AllowAnonymous();
    }

    private sealed record VAccountNotiBody(
        string? Code,
        string? Message,
        string? TransactionID,
        string? OrderID,
        string? Amount
    );
}