<?php namespace App\Models;

use Illuminate\Support\Facades\DB;

class Coupons extends Central
{
    protected $table = 'coupons';
    protected $primaryKey = 'id';
    public $module = 'coupons';

    protected $guarded = [];
    public $timestamps = false;

    public function __construct()
    {
        parent::__construct();
    }

    public static function querySelect()
    {
        return " SELECT coupons.* FROM coupons ";
    }

    public static function queryWhere()
    {
        return " WHERE coupons.id IS NOT NULL ";
    }

    public static function queryGroup()
    {
        return " ";
    }

    /**
     * Save a coupon and maintain its display rank.
     *
     * When the requested rank is occupied:
     * - Rank 10 becomes unranked.
     * - Ranks 9 down to the selected rank shift by one.
     * - The saved coupon receives the selected rank.
     *
     * @param array $data
     * @param mixed $id
     * @return mixed
     */
    public function insertRow($data, $id)
    {
        return DB::transaction(function () use ($data, $id) {
            $couponId = $id ? (int) $id : null;

            // YK-566: Verified is mandatory and defaults to true. The form's
            // hidden/checkbox pair always submits 0 or 1, so this only
            // covers callers that bypass the form (e.g. import/API).
            $requestedVerified = isset($data['verified'])
                ? (bool) $data['verified']
                : true;
            $data['verified'] = $requestedVerified;

            $previousVerified = null;
            if ($couponId !== null) {
                $existingCoupon = static::where('id', $couponId)->first();
                $previousVerified = $existingCoupon
                    ? (bool) $existingCoupon->verified
                    : null;
            }

            // YK-556: Initial Usage Count is optional. Website Copy Count
            // and Usage Count are read-only in the Admin form (never
            // rendered as inputs) - strip them here too so a tampered post
            // can't overwrite the website's counter, and so a generated
            // column (usage_count) never reaches the UPDATE/INSERT.
            if (isset($data['initial_usage_count']) && $data['initial_usage_count'] === '') {
                $data['initial_usage_count'] = null;
            }
            unset($data['website_copy_count'], $data['usage_count']);

            $storeId = !empty($data['store_id'])
                ? (int) $data['store_id']
                : null;

            $couponType = isset($data['type'])
                ? $data['type']
                : null;

            $requestedRank = isset($data['coupon_rank'])
                && $data['coupon_rank'] !== ''
                && $data['coupon_rank'] !== null
                    ? (int) $data['coupon_rank']
                    : null;

            // Offers cannot have a coupon rank.
            if ($couponType !== 'coupon') {
                $requestedRank = null;
            }

            $data['coupon_rank'] = $requestedRank;

            if (
                $storeId !== null
                && $couponType === 'coupon'
                && $requestedRank !== null
            ) {
                /*
                 * Serialize rank changes for the same store.
                 * This prevents two Admin requests from assigning
                 * the same rank simultaneously.
                 */
                DB::table('stores')
                    ->where('id', $storeId)
                    ->lockForUpdate()
                    ->first();

                $currentCoupon = null;

                if ($couponId !== null) {
                    $currentCoupon = static::where('id', $couponId)
                        ->lockForUpdate()
                        ->first();
                }

                $occupiedRankQuery = static::where('store_id', $storeId)
                    ->where('type', 'coupon')
                    ->where('coupon_rank', $requestedRank);

                if ($couponId !== null) {
                    $occupiedRankQuery->where('id', '!=', $couponId);
                }

                if ($occupiedRankQuery->exists()) {
                    /*
                     * Temporarily unrank the coupon being edited to avoid
                     * unique-index collisions while subsequent ranks shift.
                     */
                    if (
                        $currentCoupon
                        && (int) $currentCoupon->store_id === $storeId
                        && $currentCoupon->type === 'coupon'
                        && $currentCoupon->coupon_rank !== null
                    ) {
                        static::where('id', $couponId)->update([
                            'coupon_rank' => null,
                        ]);
                    }
                    /*
                     * Rank 10 cannot become 11 because the accepted
                     * range is 1–10. It becomes unranked instead.
                     */
                    $rankTenQuery = static::where('store_id', $storeId)
                        ->where('type', 'coupon')
                        ->where('coupon_rank', 10);

                    if ($couponId !== null) {
                        $rankTenQuery->where('id', '!=', $couponId);
                    }

                    $rankTenQuery->update([
                        'coupon_rank' => null,
                    ]);

                    /*
                     * Update in descending order to avoid temporary
                     * duplicate values with the unique index.
                     */
                    for (
                        $currentRank = 9;
                        $currentRank >= $requestedRank;
                        $currentRank--
                    ) {
                        $shiftQuery = static::where('store_id', $storeId)
                            ->where('type', 'coupon')
                            ->where('coupon_rank', $currentRank);

                        if ($couponId !== null) {
                            $shiftQuery->where('id', '!=', $couponId);
                        }

                        $shiftQuery->update([
                            'coupon_rank' => $currentRank + 1,
                        ]);
                    }
                }
            }

            $savedId = parent::insertRow($data, $id);

            // YK-566: log the verification action (user, via auditTrail's
            // user_id/logdate columns) whenever it's newly set or changed -
            // not on every unrelated coupon edit.
            if ($previousVerified === null || $previousVerified !== $requestedVerified) {
                \SiteHelpers::auditTrail(
                    request(),
                    'Coupon ID : ' . ($couponId ?? $savedId) . ' , Verified set to "'
                        . ($requestedVerified ? 'Verified' : 'Not Verified') . '"'
                );
            }

            return $savedId;
        });
    }
}
