<?php


namespace App\Services\tcc;


use Api\PhpUtils\Common\BaseConvert;
use App\Exception\custom\GoodsException;
use App\Models\goods\mysql\GoodsSku;
use App\Models\goods\mysql\Tcc;

class TccService
{
    const TCC_RESULT_FAIL = 0;
    const TCC_RESULT_SUCCESS = 1;

    /**
     * 下单 商品tcc try
     * @param $goodsSkuId
     * @param $tid
     * @return int
     */
    public static function placeAnOrderTry($goodsSkuId, $tid)
    {
        $tccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_TRY]);
        //有结果返回原来的结果，幂等
        if (!empty($tccInfo)) {
            if ($tccInfo[0]["operator_result"] == Tcc::OPERATOR_RESULT_FAIL) {
                return self::TCC_RESULT_FAIL;
            } else {
                return self::TCC_RESULT_SUCCESS;
            }
        }

        //如果已经有 confirm 或者 cancel，则直接失败
        $cTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => [Tcc::STATUS_CONFIRM, Tcc::STATUS_CANCEL], "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (!empty($cTccInfo)) {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_TRY,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }


        $sku = GoodsSku::getRecord(["goods_sku_id" => $goodsSkuId]);
        if (!empty($sku["inventory_rest"]) && $sku["online_status"] == GoodsSku::ONLINE_STATUS_ONLINE) {
            GoodsSku::beginTransaction();
            GoodsSku::save([
                "inventory_lock" => $sku["inventory_lock"] + 1,
                "inventory_rest" => $sku["inventory_rest"] - 1,
            ], ["goods_sku_id" => $goodsSkuId]);

            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_TRY,
                "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS,
            ]);

            if (!GoodsSku::commit()) {
                GoodsSku::rollback();

                Tcc::save([
                    "t_id" => $tid,
                    "goods_sku_id" => $goodsSkuId,
                    "status" => Tcc::STATUS_TRY,
                    "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
                ]);
                return self::TCC_RESULT_FAIL;
            }
        } else {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_TRY,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        return self::TCC_RESULT_SUCCESS;
    }

    /**
     * 下单 商品tcc confirm
     * @param $goodsSkuId
     * @param $tid
     * @return int
     */
    public static function placeAnOrderConfirm($goodsSkuId, $tid)
    {
        $tccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CONFIRM]);
        //有结果返回原来的结果，幂等
        if (!empty($tccInfo)) {
            if ($tccInfo[0]["operator_result"] == Tcc::OPERATOR_RESULT_FAIL) {
                return self::TCC_RESULT_FAIL;
            } else {
                return self::TCC_RESULT_SUCCESS;
            }
        }

        //在confirm时候必须已经有try，如果没有就直接返回fail
        $tryTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_TRY, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (empty($tryTccInfo)) {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CONFIRM,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        //如果已经 cancel 成功
        $cancelTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CANCEL, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (!empty($cancelTccInfo)) {
            return self::TCC_RESULT_FAIL;
        }

        $sku = GoodsSku::getRecord(["goods_sku_id" => $goodsSkuId]);
        if (!empty($sku["inventory_rest"]) && $sku["online_status"] == GoodsSku::ONLINE_STATUS_ONLINE) {
            GoodsSku::beginTransaction();
            GoodsSku::save([
                "inventory_lock" => $sku["inventory_lock"] - 1,
                "total_amount_order" => $sku["total_amount_order"] + 1,
            ], ["goods_sku_id" => $goodsSkuId]);

            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CONFIRM,
                "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS,
            ]);

            if (!GoodsSku::commit()) {
                GoodsSku::rollback();

                Tcc::save([
                    "t_id" => $tid,
                    "goods_sku_id" => $goodsSkuId,
                    "status" => Tcc::STATUS_CONFIRM,
                    "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
                ]);
                return self::TCC_RESULT_FAIL;
            }
        } else {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CONFIRM,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        return self::TCC_RESULT_SUCCESS;
    }

    /**
     * 下单 商品tcc cancel
     * @param $goodsSkuId
     * @param $tid
     * @return int
     */
    public static function placeAnOrderCancel($goodsSkuId, $tid)
    {
        $tccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CANCEL]);
        //有结果返回原来的结果，幂等
        if (!empty($tccInfo)) {
            if ($tccInfo[0]["operator_result"] == Tcc::OPERATOR_RESULT_FAIL) {
                return self::TCC_RESULT_FAIL;
            } else {
                return self::TCC_RESULT_SUCCESS;
            }
        }

        //在cancel时候必须已经有try，如果没有就直接返回fail
        $tryTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_TRY, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (empty($tryTccInfo)) {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CANCEL,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        //如果已经 confirm 成功
        $confirmTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CONFIRM, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (!empty($confirmTccInfo)) {
            return self::TCC_RESULT_FAIL;
        }

        $sku = GoodsSku::getRecord(["goods_sku_id" => $goodsSkuId]);
        if (!empty($sku["inventory_rest"]) && $sku["online_status"] == GoodsSku::ONLINE_STATUS_ONLINE) {
            GoodsSku::beginTransaction();
            GoodsSku::save([
                "inventory_lock" => $sku["inventory_lock"] - 1,
                "inventory_rest" => $sku["inventory_rest"] + 1,
            ], ["goods_sku_id" => $goodsSkuId]);

            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CANCEL,
                "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS,
            ]);

            if (!GoodsSku::commit()) {
                GoodsSku::rollback();

                Tcc::save([
                    "t_id" => $tid,
                    "goods_sku_id" => $goodsSkuId,
                    "status" => Tcc::STATUS_CANCEL,
                    "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
                ]);
                return self::TCC_RESULT_FAIL;
            }
        } else {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CANCEL,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        return self::TCC_RESULT_SUCCESS;
    }

    /**
     * 取消订单单 商品tcc try
     * @param $goodsSkuId
     * @param $tid
     * @return int
     */
    public static function cancelOrderTry($goodsSkuId, $tid)
    {
        $tccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_TRY]);
        //有结果返回原来的结果，幂等
        if (!empty($tccInfo)) {
            if ($tccInfo[0]["operator_result"] == Tcc::OPERATOR_RESULT_FAIL) {
                return self::TCC_RESULT_FAIL;
            } else {
                return self::TCC_RESULT_SUCCESS;
            }
        }

        //如果已经有 confirm 或者 cancel，则直接失败
        $cTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => [Tcc::STATUS_CONFIRM, Tcc::STATUS_CANCEL], "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (!empty($cTccInfo)) {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_TRY,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        $sku = GoodsSku::getRecord(["goods_sku_id" => $goodsSkuId]);
        if (!empty($sku["inventory_rest"]) && $sku["online_status"] == GoodsSku::ONLINE_STATUS_ONLINE) {
            GoodsSku::beginTransaction();
            GoodsSku::save([
                "inventory_lock" => $sku["inventory_lock"] + 1,
                "total_amount_order" => $sku["total_amount_order"] - 1,
            ], ["goods_sku_id" => $goodsSkuId]);

            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_TRY,
                "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS,
            ]);

            if (!GoodsSku::commit()) {
                GoodsSku::rollback();

                Tcc::save([
                    "t_id" => $tid,
                    "goods_sku_id" => $goodsSkuId,
                    "status" => Tcc::STATUS_TRY,
                    "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
                ]);
                return self::TCC_RESULT_FAIL;
            }
        } else {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_TRY,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        return self::TCC_RESULT_SUCCESS;
    }

    /**
     * 取消订单单 商品tcc confirm
     * @param $goodsSkuId
     * @param $tid
     * @return int
     */
    public static function cancelOrderConfirm($goodsSkuId, $tid)
    {
        $tccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CONFIRM]);
        //有结果返回原来的结果，幂等
        if (!empty($tccInfo)) {
            if ($tccInfo[0]["operator_result"] == Tcc::OPERATOR_RESULT_FAIL) {
                return self::TCC_RESULT_FAIL;
            } else {
                return self::TCC_RESULT_SUCCESS;
            }
        }

        //在confirm时候必须已经有try，如果没有就直接返回fail
        $tryTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_TRY, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (empty($tryTccInfo)) {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CONFIRM,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        //如果已经 cancel 成功
        $cancelTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CANCEL, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (!empty($cancelTccInfo)) {
            return self::TCC_RESULT_FAIL;
        }

        $sku = GoodsSku::getRecord(["goods_sku_id" => $goodsSkuId]);
        if (!empty($sku["inventory_rest"]) && $sku["online_status"] == GoodsSku::ONLINE_STATUS_ONLINE) {
            GoodsSku::beginTransaction();
            GoodsSku::save([
                "inventory_lock" => $sku["inventory_lock"] - 1,
                "inventory_rest" => $sku["inventory_rest"] + 1,
            ], ["goods_sku_id" => $goodsSkuId]);

            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CONFIRM,
                "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS,
            ]);

            if (!GoodsSku::commit()) {
                GoodsSku::rollback();

                Tcc::save([
                    "t_id" => $tid,
                    "goods_sku_id" => $goodsSkuId,
                    "status" => Tcc::STATUS_CONFIRM,
                    "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
                ]);
                return self::TCC_RESULT_FAIL;
            }
        } else {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CONFIRM,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        return self::TCC_RESULT_SUCCESS;
    }

    /**
     * 取消订单单 商品tcc cancel
     * @param $goodsSkuId
     * @param $tid
     * @return int
     */
    public static function cancelOrderCancel($goodsSkuId, $tid)
    {
        $tccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CANCEL]);
        //有结果返回原来的结果，幂等
        if (!empty($tccInfo)) {
            if ($tccInfo[0]["operator_result"] == Tcc::OPERATOR_RESULT_FAIL) {
                return self::TCC_RESULT_FAIL;
            } else {
                return self::TCC_RESULT_SUCCESS;
            }
        }

        //在cancel时候必须已经有try，如果没有就直接返回fail
        $tryTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_TRY, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (empty($tryTccInfo)) {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CANCEL,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        //如果已经 confirm 成功
        $confirmTccInfo = Tcc::getRecordMaster(["t_id" => $tid, "goods_sku_id" => $goodsSkuId, "status" => Tcc::STATUS_CONFIRM, "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS]);
        if (!empty($confirmTccInfo)) {
            return self::TCC_RESULT_FAIL;
        }

        $sku = GoodsSku::getRecord(["goods_sku_id" => $goodsSkuId]);
        if (!empty($sku["inventory_rest"]) && $sku["online_status"] == GoodsSku::ONLINE_STATUS_ONLINE) {
            GoodsSku::beginTransaction();
            GoodsSku::save([
                "inventory_lock" => $sku["inventory_lock"] - 1,
                "total_amount_order" => $sku["total_amount_order"] + 1,
            ], ["goods_sku_id" => $goodsSkuId]);

            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CANCEL,
                "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS,
            ]);

            if (!GoodsSku::commit()) {
                GoodsSku::rollback();

                Tcc::save([
                    "t_id" => $tid,
                    "goods_sku_id" => $goodsSkuId,
                    "status" => Tcc::STATUS_CANCEL,
                    "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
                ]);
                return self::TCC_RESULT_FAIL;
            }
        } else {
            Tcc::save([
                "t_id" => $tid,
                "goods_sku_id" => $goodsSkuId,
                "status" => Tcc::STATUS_CANCEL,
                "operator_result" => Tcc::OPERATOR_RESULT_FAIL,
            ]);
            return self::TCC_RESULT_FAIL;
        }

        return self::TCC_RESULT_SUCCESS;
    }

    /**
     * 判断一个tcc是否完成
     * @param $goodsSkuId
     * @param $tid
     * @return int
     */
    public static function tccIsFinish($goodsSkuId, $tid)
    {
        $tccInfo = Tcc::getRecord([
            "t_id" => $tid,
            "goods_sku_id" => $goodsSkuId,
            "status" => [Tcc::STATUS_CONFIRM, Tcc::STATUS_CANCEL],
            "operator_result" => Tcc::OPERATOR_RESULT_SUCCESS,
        ]);

        if (!empty($tccInfo)) {
            return self::TCC_RESULT_SUCCESS;
        }
        return self::TCC_RESULT_FAIL;
    }
}