<?php

namespace App\Domain\Identity\Services;

use App\Domain\Identity\Models\Branch;
use App\Domain\Identity\Models\BranchSetting;

class BranchSettingsService
{
    /**
     * A branch whose takings never pass through this system.
     *
     * A partner-run site, or one whose money is banked elsewhere: participants
     * enrol there without being billed, and the branch's income is entered
     * afterwards on the external-revenue screen as a single figure.
     */
    public const KEY_BILLING_EXTERNAL = 'billing.handled_externally';

    /** Answers within one request, since the gates below ask per enrolment. */
    private array $externalBillingCache = [];

    /**
     * Whether this branch's subscription money is handled outside the system.
     *
     * This is the branch-wide counterpart of participants.is_free, and it
     * behaves identically: no invoice is raised at all rather than a zero one.
     * A zero-total invoice is precisely what AccountAnomalyScanner reports as
     * corruption, so writing one per registration would fill the anomaly
     * worklist with rows that are working as intended.
     */
    public function billingHandledExternally(?int $branchId): bool
    {
        if ($branchId === null) {
            return false;
        }

        // Read straight off the branch row rather than through get(). Two
        // reasons: this key is per branch and has no academy-wide meaning, so
        // the fallback could only ever match a system setting that happened to
        // share its name; and the renewal command asks this question from the
        // console, where there is no current academy to fall back through.
        return $this->externalBillingCache[$branchId] ??= filter_var(
            BranchSetting::where('branch_id', $branchId)
                ->where('key', self::KEY_BILLING_EXTERNAL)
                ->value('value'),
            FILTER_VALIDATE_BOOLEAN
        );
    }

    /**
     * Get a setting value for a branch. Falls back to academy-level system_settings.
     */
    public function get(int $branchId, string $key, mixed $default = null): mixed
    {
        $setting = BranchSetting::where('branch_id', $branchId)
            ->where('key', $key)
            ->first();

        if ($setting) {
            return $setting->value;
        }

        // Fall back to academy-level setting. app()->has() first: outside a
        // request — a console command, a queued job — nothing has bound
        // current_academy, and app() on an unbound key throws rather than
        // returning null.
        $academy = app()->has('current_academy') ? app('current_academy') : null;
        if ($academy) {
            $systemSetting = \DB::table('system_settings')
                ->where('academy_id', $academy->id)
                ->where('key', $key)
                ->first();

            if ($systemSetting) {
                return $systemSetting->value;
            }
        }

        return $default;
    }

    /**
     * Set a branch-level setting.
     */
    public function set(int $branchId, string $key, mixed $value, string $group = 'general'): void
    {
        $academy = app()->has('current_academy') ? app('current_academy') : null;

        BranchSetting::updateOrCreate(
            ['branch_id' => $branchId, 'key' => $key],
            [
                'academy_id' => $academy?->id,
                'value' => is_array($value) ? json_encode($value) : (string) $value,
                'group' => $group,
            ]
        );
    }

    /**
     * Get all settings for a branch (merged with academy defaults).
     */
    public function allForBranch(int $branchId): array
    {
        $branchSettings = BranchSetting::where('branch_id', $branchId)
            ->pluck('value', 'key')
            ->toArray();

        $academy = app()->has('current_academy') ? app('current_academy') : null;
        $academySettings = [];
        if ($academy) {
            $academySettings = \DB::table('system_settings')
                ->where('academy_id', $academy->id)
                ->pluck('value', 'key')
                ->toArray();
        }

        // Branch overrides academy
        return array_merge($academySettings, $branchSettings);
    }

    /**
     * Get receipt configuration for a branch.
     */
    public function getReceiptConfig(int $branchId): array
    {
        $settings = BranchSetting::where('branch_id', $branchId)
            ->where('group', 'receipt')
            ->pluck('value', 'key')
            ->toArray();

        return array_merge([
            'receipt_header_show_logo' => 'true',
            'receipt_header_show_branch_name' => 'true',
            'receipt_header_show_branch_address' => 'true',
            'receipt_header_show_branch_phone' => 'true',
            'receipt_show_cashier' => 'true',
            'receipt_show_participant' => 'true',
            'receipt_show_tax' => 'true',
            'receipt_show_discount_details' => 'true',
            'receipt_show_payment_method' => 'true',
            'receipt_show_invoice_number' => 'false',
            'receipt_show_qr' => 'false',
            'receipt_footer_text' => 'شكراً لزيارتكم',
            'receipt_return_policy' => 'لا يمكن استرجاع المبلغ بعد 7 أيام',
            'receipt_paper_width' => '80mm',
        ], $settings);
    }
}
