using System;

namespace MJGameSDK
{
    public class MJGameIAP
    {
        private readonly MJGameHttpClient _http;
        private readonly MJGameSteamManager _steam;
        private const float MicroTxnTimeoutSeconds = 120f;

        public MJGameIAP(MJGameHttpClient http, MJGameSteamManager steam)
        {
            _http = http;
            _steam = steam;
        }

        public void GetProducts(Action<MJGameProduct[]> onSuccess, Action<MJGameResult> onError)
        {
            _http.Get<ProductListResponse>("iap/products",
                response => onSuccess?.Invoke(response.data.products ?? Array.Empty<MJGameProduct>()),
                onError);
        }

        /// <summary>
        /// 完整购买流程：服务端 InitTxn → Steam Overlay 授权 → 服务端 FinalizeTxn → 平台回调游戏服发货。
        /// </summary>
        public void Purchase(string productId, Action<MJGameOrder> onSuccess, Action<MJGameResult> onError)
        {
            Purchase(productId, null, onSuccess, onError);
        }

        public void Purchase(
            string productId,
            MJGamePurchaseContext context,
            Action<MJGameOrder> onSuccess,
            Action<MJGameResult> onError)
        {
            var startBody = BuildPurchaseStartRequest(productId, context);

            _http.Post<PurchaseStartResponse>("iap/purchase/start", startBody,
                startResponse =>
                {
                    var order = startResponse.data.order;
                    if (order == null || string.IsNullOrEmpty(order.order_id))
                    {
                        onError?.Invoke(MJGameResult.Fail(3003, "Invalid purchase start response"));
                        return;
                    }

                    MJGameLogger.Info("IAP", $"Purchase started: orderId={order.order_id}, product={productId}");

                    if (!ulong.TryParse(order.order_id, out var steamOrderId))
                    {
                        onError?.Invoke(MJGameResult.Fail(3007, $"Invalid order id format: {order.order_id}"));
                        return;
                    }

                    _steam.WaitForMicroTxnAuthorization(
                        steamOrderId,
                        () => ConfirmPurchase(productId, order.order_id, onSuccess, onError),
                        denied =>
                        {
                            CancelPurchase(order.order_id, _ => { }, _ => { });
                            onError?.Invoke(denied);
                        },
                        MicroTxnTimeoutSeconds);
                },
                onError);
        }

        public void GetOrders(Action<MJGameOrder[]> onSuccess, Action<MJGameResult> onError)
        {
            _http.Get<OrderListResponse>("iap/orders",
                response => onSuccess?.Invoke(response.data.orders ?? Array.Empty<MJGameOrder>()),
                onError);
        }

        private static PurchaseStartRequest BuildPurchaseStartRequest(string productId, MJGamePurchaseContext context)
        {
            var body = new PurchaseStartRequest
            {
                product_id = productId,
                language = "en"
            };

            if (context == null)
            {
                return body;
            }

            body.server_id = context.server_id;
            body.server_name = context.server_name;
            body.role_id = context.role_id;
            body.role_name = context.role_name;
            body.extra = TruncateExtra(context.extra);

            return body;
        }

        private static string TruncateExtra(string extra)
        {
            if (string.IsNullOrEmpty(extra))
            {
                return null;
            }

            return extra.Length <= 255 ? extra : extra.Substring(0, 255);
        }

        private void ConfirmPurchase(
            string productId,
            string orderId,
            Action<MJGameOrder> onSuccess,
            Action<MJGameResult> onError)
        {
            var body = new PurchaseConfirmRequest
            {
                product_id = productId,
                order_id = orderId
            };

            _http.Post<PurchaseConfirmResponse>("iap/purchase/confirm", body,
                response =>
                {
                    var order = response.data.order;
                    if (order == null || order.status != "completed")
                    {
                        onError?.Invoke(MJGameResult.Fail(3008, "Game delivery not completed"));
                        return;
                    }

                    MJGameLogger.Info("IAP", $"Purchase success: orderId={order.order_id}");
                    onSuccess?.Invoke(order);
                },
                onError);
        }

        private void CancelPurchase(string orderId, Action<MJGameOrder> onSuccess, Action<MJGameResult> onError)
        {
            var body = new PurchaseCancelRequest { order_id = orderId };

            _http.Post<PurchaseCancelResponse>("iap/purchase/cancel", body,
                response =>
                {
                    MJGameLogger.Info("IAP", $"Purchase cancelled: orderId={orderId}");
                    onSuccess?.Invoke(response.data.order);
                },
                onError);
        }
    }

    [Serializable]
    public class MJGamePurchaseContext
    {
        public string server_id;
        public string server_name;
        public string role_id;
        public string role_name;
        /// <summary>游戏自定义字段，服务端原样回传游戏发货接口，最长 255 字符。</summary>
        public string extra;
    }

    [Serializable]
    public class MJGameProduct
    {
        public string product_id;
        public string name;
        public string description;
        public int price_cents;
        public string currency;
    }

    [Serializable]
    public class MJGameOrder
    {
        public int id;
        public string order_id;
        public string product_id;
        public string status;
        public int amount_cents;
        public string currency;
        public string created_at;
    }

    [Serializable]
    public class ProductListResponse : MJGameResponse
    {
        public ProductListData data;
    }

    [Serializable]
    public class ProductListData
    {
        public MJGameProduct[] products;
    }

    [Serializable]
    public class PurchaseStartRequest
    {
        public string product_id;
        public string language;
        public string server_id;
        public string server_name;
        public string role_id;
        public string role_name;
        public string extra;
    }

    [Serializable]
    public class PurchaseStartResponse : MJGameResponse
    {
        public PurchaseStartData data;
    }

    [Serializable]
    public class PurchaseStartData
    {
        public MJGameOrder order;
        public string steam_trans_id;
    }

    [Serializable]
    public class PurchaseConfirmRequest
    {
        public string product_id;
        public string order_id;
    }

    [Serializable]
    public class PurchaseConfirmResponse : MJGameResponse
    {
        public PurchaseConfirmData data;
    }

    [Serializable]
    public class PurchaseConfirmData
    {
        public MJGameOrder order;
    }

    [Serializable]
    public class PurchaseCancelRequest
    {
        public string order_id;
    }

    [Serializable]
    public class PurchaseCancelResponse : MJGameResponse
    {
        public PurchaseCancelData data;
    }

    [Serializable]
    public class PurchaseCancelData
    {
        public MJGameOrder order;
    }

    [Serializable]
    public class OrderListResponse : MJGameResponse
    {
        public OrderListData data;
    }

    [Serializable]
    public class OrderListData
    {
        public MJGameOrder[] orders;
    }
}
