<?php

namespace Modules\VetClinic\Services;

use App\Contact;
use Illuminate\Support\Facades\DB;
use Modules\VetClinic\Entities\VcBlockSetting;
use Modules\VetClinic\Entities\VcEvaluation;
use Modules\VetClinic\Entities\VcPetOwnerDetail;

/**
 * Item 3.1 / 3.2 — Owner-blocking policy engine.
 *
 *  evaluateAfterRating()   - called after every pet-owner evaluation
 *                            save. Recomputes the owner's cumulative
 *                            score and auto-blocks if it falls below
 *                            the configured threshold.
 *
 *  block(detail, reason)   - applies the block: marks the detail row,
 *                            snapshots + zeroes the contact credit
 *                            limit (if policy says so), writes the
 *                            block_avg_rating / count for reviewer
 *                            context.
 *
 *  unblock(detail, restore)- clears the block. If $restore is true the
 *                            previously snapshotted credit_limit_backup
 *                            is restored to the contact; otherwise the
 *                            credit limit stays at zero.
 *
 *  isBlockedContact($cid)  - cheap check used at appointment-booking
 *                            and invoice-creation gates to refuse
 *                            transactions for blocked owners.
 */
class OwnerBlockService
{
    /**
     * Re-score an owner after a new evaluation lands and auto-block if
     * they cross the threshold. Returns the block result or null if no
     * action was taken.
     *
     * Safe to call multiple times - already-blocked owners are skipped,
     * owners below the minimum rating count are skipped.
     */
    public function evaluateAfterRating(int $businessId, int $contactId): ?array
    {
        $settings = VcBlockSetting::forBusiness($businessId);
        if (!$settings->enable_auto_block) return null;

        $detail = VcPetOwnerDetail::where('business_id', $businessId)
            ->where('contact_id', $contactId)->first();
        if (!$detail || $detail->is_blocked) return null;

        $ratings = VcEvaluation::where('business_id', $businessId)
            ->where('contact_id', $contactId)
            ->where('category', 'pet_owner')
            ->whereNotNull('avg_rating')
            ->get(['avg_rating']);

        $count = $ratings->count();
        if ($count < $settings->min_ratings_to_evaluate) {
            return null; // not enough data to act
        }
        $avg = round($ratings->avg('avg_rating'), 2);   // 0-5 scale
        $percent = round(($avg / 5) * 100);

        if ($percent >= $settings->block_rating_threshold) return null;

        $this->block(
            $detail,
            sprintf(
                'Auto-blocked: cumulative rating %.2f/5 (%d%%) over %d ratings is below the %d%% threshold.',
                $avg, $percent, $count, $settings->block_rating_threshold
            ),
            null, // no user id - automated
            $settings->block_zero_credit_limit,
            $avg, $count
        );
        return ['blocked' => true, 'avg' => $avg, 'percent' => $percent, 'count' => $count];
    }

    public function block(
        VcPetOwnerDetail $detail,
        string $reason,
        ?int $byUserId = null,
        bool $zeroCreditLimit = true,
        ?float $avg = null,
        ?int $count = null
    ): void {
        // Snapshot the contact's current credit limit so we can restore
        // later if the admin wants to. Then optionally zero it.
        $contact = Contact::find($detail->contact_id);
        $backup = $contact ? $contact->credit_limit : null;

        $detail->forceFill([
            'is_blocked'           => true,
            'blocked_at'           => now(),
            'blocked_reason'       => $reason,
            'blocked_by'           => $byUserId,
            'credit_limit_backup'  => $backup,
            'block_avg_rating'     => $avg,
            'block_rating_count'   => $count,
        ])->save();

        if ($zeroCreditLimit && $contact) {
            $contact->credit_limit = 0;
            $contact->save();
        }
    }

    public function unblock(VcPetOwnerDetail $detail, bool $restoreCreditLimit, ?int $byUserId = null): void
    {
        if ($restoreCreditLimit && $detail->credit_limit_backup !== null) {
            $contact = Contact::find($detail->contact_id);
            if ($contact) {
                $contact->credit_limit = $detail->credit_limit_backup;
                $contact->save();
            }
        }
        $detail->forceFill([
            'is_blocked'          => false,
            'blocked_at'          => null,
            'blocked_reason'      => null,
            'blocked_by'          => null,
            'credit_limit_backup' => null,
            'block_avg_rating'    => null,
            'block_rating_count'  => null,
        ])->save();
    }

    /** Cheap booking-gate check. */
    public function isBlockedContact(int $businessId, ?int $contactId): bool
    {
        if (!$contactId) return false;
        return VcPetOwnerDetail::where('business_id', $businessId)
            ->where('contact_id', $contactId)
            ->where('is_blocked', true)
            ->exists();
    }
}
