<?php

namespace App\Support;

use App\Models\Setting;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Schema;

class WelcomeOfferSettings
{
    public const AMOUNT_FIELD = 'welcome_offer_amount';

    public static function definitions(): array
    {
        return [
            'amount' => [
                'field' => 'welcome_offer_amount',
                'setting_key' => 'welcome_offer_amount',
                'label' => 'Reward Amount (BDT)',
                'type' => 'number',
                'default' => '0',
                'step' => '0.01',
                'min' => '0',
                'rules' => ['required', 'numeric', 'min:0', 'max:9999999.99'],
                'help' => 'ইউজার panel-এর top reward card-এ এই amount show হবে।',
            ],
            'launch_starts_at' => [
                'field' => 'welcome_offer_launch_starts_at',
                'setting_key' => 'welcome_offer_launch_starts_at',
                'label' => 'Start Counting From',
                'type' => 'datetime-local',
                'default' => '',
                'rules' => ['required', 'date_format:Y-m-d\\TH:i'],
                'help' => 'এই সময়ের আগে verify হওয়া member Welcome Offer level count হবে না। এখন থেকে নতুন করে count শুরু করতে এই cutoff use হবে।',
            ],
            'level_one_target' => [
                'field' => 'welcome_offer_level_one_target',
                'setting_key' => 'welcome_offer_level_one_target',
                'label' => 'Level 1 Target',
                'type' => 'number',
                'default' => '15',
                'step' => '1',
                'min' => '1',
                'rules' => ['required', 'integer', 'min:1', 'max:99999'],
                'help' => 'প্রথম লেভেলে কত verified member count হবে।',
            ],
            'level_two_target' => [
                'field' => 'welcome_offer_level_two_target',
                'setting_key' => 'welcome_offer_level_two_target',
                'label' => 'Level 2 Target',
                'type' => 'number',
                'default' => '10',
                'step' => '1',
                'min' => '1',
                'rules' => ['required', 'integer', 'min:1', 'max:99999'],
                'help' => 'দ্বিতীয় লেভেলে কত verified member count হবে।',
            ],
            'level_one_label' => [
                'field' => 'welcome_offer_level_one_label',
                'setting_key' => 'welcome_offer_level_one_label',
                'label' => 'Level 1 Label',
                'type' => 'text',
                'default' => 'প্রথম লেভেল',
                'rules' => ['required', 'string', 'max:120'],
                'help' => 'Counter card ও history page-এ level 1 এর নাম।',
            ],
            'level_two_label' => [
                'field' => 'welcome_offer_level_two_label',
                'setting_key' => 'welcome_offer_level_two_label',
                'label' => 'Level 2 Label',
                'type' => 'text',
                'default' => 'দ্বিতীয় লেভেল',
                'rules' => ['required', 'string', 'max:120'],
                'help' => 'Counter card ও history page-এ level 2 এর নাম।',
            ],
            'page_title' => [
                'field' => 'welcome_offer_page_title',
                'setting_key' => 'welcome_offer_page_title',
                'label' => 'Page Title',
                'type' => 'text',
                'default' => 'টার্গেট পূরণ করলে পাবেন ৳:amount',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Available tokens: :amount',
            ],
            'page_summary' => [
                'field' => 'welcome_offer_page_summary',
                'setting_key' => 'welcome_offer_page_summary',
                'label' => 'Page Summary',
                'type' => 'textarea',
                'default' => 'প্রথম লেভেলে :level1_target জন verified member এবং দ্বিতীয় লেভেলে :level2_target জন verified member count হলে welcome offer target complete ধরা হবে।',
                'rules' => ['required', 'string', 'max:1000'],
                'help' => 'Available tokens: :level1_target, :level2_target',
            ],
            'status_ready_text' => [
                'field' => 'welcome_offer_status_ready_text',
                'setting_key' => 'welcome_offer_status_ready_text',
                'label' => 'Completed Status Text',
                'type' => 'text',
                'default' => 'টার্গেট পূরণ হয়েছে',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'দুই target complete হলে এই text show হবে।',
            ],
            'status_pending_text' => [
                'field' => 'welcome_offer_status_pending_text',
                'setting_key' => 'welcome_offer_status_pending_text',
                'label' => 'Pending Status Text',
                'type' => 'text',
                'default' => 'Verified member count live data থেকে চলছে',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'টার্গেট complete না হলে এই text show হবে।',
            ],
            'notice_title' => [
                'field' => 'welcome_offer_notice_title',
                'setting_key' => 'welcome_offer_notice_title',
                'label' => 'Notice Title',
                'type' => 'text',
                'default' => 'আপডেট নোটিশ',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Notice card-এর heading।',
            ],
            'notice_body' => [
                'field' => 'welcome_offer_notice_body',
                'setting_key' => 'welcome_offer_notice_body',
                'label' => 'Notice Body',
                'type' => 'textarea',
                'default' => 'এই page-এ verified member ছাড়া কাউকে count করা হবে না। Count card-এ click করলে ঐ level-এর verified member list table আকারে দেখাবে।',
                'rules' => ['required', 'string', 'max:1200'],
                'help' => 'Main notice paragraph।',
            ],
            'level_one_note' => [
                'field' => 'welcome_offer_level_one_note',
                'setting_key' => 'welcome_offer_level_one_note',
                'label' => 'Level 1 Note',
                'type' => 'textarea',
                'default' => 'Direct referral verified হলেই এখানে count হবে।',
                'rules' => ['required', 'string', 'max:600'],
                'help' => 'Notice card-এ level 1 box-এর text।',
            ],
            'level_two_note' => [
                'field' => 'welcome_offer_level_two_note',
                'setting_key' => 'welcome_offer_level_two_note',
                'label' => 'Level 2 Note',
                'type' => 'textarea',
                'default' => 'প্রথম লেভেলের referral-এর নিচের verified member count হবে।',
                'rules' => ['required', 'string', 'max:600'],
                'help' => 'Notice card-এ level 2 box-এর text।',
            ],
            'history_note' => [
                'field' => 'welcome_offer_history_note',
                'setting_key' => 'welcome_offer_history_note',
                'label' => 'History Note',
                'type' => 'textarea',
                'default' => 'Member name, referral, mobile, verify time সব table-এ দেখাবে।',
                'rules' => ['required', 'string', 'max:600'],
                'help' => 'Notice card-এ history box-এর text।',
            ],
        ];
    }

    public static function validationRules(): array
    {
        $rules = [];

        foreach (static::definitions() as $definition) {
            $rules[$definition['field']] = (array) ($definition['rules'] ?? ['nullable', 'string', 'max:255']);
        }

        return $rules;
    }

    public static function inputValues(): array
    {
        $settings = static::settingsMap();
        $values = [];

        foreach (static::definitions() as $key => $definition) {
            if ($key === 'launch_starts_at') {
                $values[$key] = static::launchStartsAt()->format('Y-m-d\\TH:i');
                continue;
            }

            $values[$key] = (string) ($settings[$definition['setting_key']] ?? $definition['default'] ?? '');
        }

        return $values;
    }

    public static function amount(): float
    {
        return round((float) static::inputValueByKey('amount'), 2);
    }

    /**
     * @return array<int, int>
     */
    public static function targets(): array
    {
        return [
            1 => max(1, (int) static::inputValueByKey('level_one_target')),
            2 => max(1, (int) static::inputValueByKey('level_two_target')),
        ];
    }

    /**
     * @return array<int, string>
     */
    public static function labels(): array
    {
        return [
            1 => trim((string) static::inputValueByKey('level_one_label')) ?: 'প্রথম লেভেল',
            2 => trim((string) static::inputValueByKey('level_two_label')) ?: 'দ্বিতীয় লেভেল',
        ];
    }

    public static function launchStartsAt(): Carbon
    {
        if (!Schema::hasTable('settings')) {
            return now();
        }

        $value = Setting::query()
            ->where('key', 'welcome_offer_launch_starts_at')
            ->orderByDesc('id')
            ->value('value');

        try {
            if (is_string($value) && trim($value) !== '') {
                return Carbon::parse($value);
            }
        } catch (\Throwable) {
        }

        $timestamp = now()->startOfMinute();
        static::saveSettingValue('welcome_offer_launch_starts_at', $timestamp->format('Y-m-d H:i:s'));

        return $timestamp;
    }

    public static function content(): array
    {
        $values = static::inputValues();
        $labels = static::labels();
        $targets = static::targets();
        $amount = number_format(static::amount(), 2, '.', '');
        $tokens = [
            ':amount' => $amount,
            ':level1_target' => (string) $targets[1],
            ':level2_target' => (string) $targets[2],
            ':level1_label' => (string) $labels[1],
            ':level2_label' => (string) $labels[2],
            ':launch_at' => static::launchStartsAt()->format('d M Y, h:i A'),
        ];

        foreach ($values as $key => $value) {
            $values[$key] = strtr((string) $value, $tokens);
        }

        return $values;
    }

    public static function inputValue(): string
    {
        return static::inputValueByKey('amount');
    }

    public static function saveInputValues(array $values): void
    {
        foreach (static::definitions() as $key => $definition) {
            $field = (string) $definition['field'];
            $value = $values[$field] ?? ($definition['default'] ?? '');
            static::saveSettingValue((string) $definition['setting_key'], static::normalizeValue($key, $value));
        }
    }

    public static function saveInputValue(mixed $value): void
    {
        static::saveInputValues([
            static::AMOUNT_FIELD => $value,
        ]);
    }

    private static function inputValueByKey(string $key): string
    {
        $definition = static::definitions()[$key] ?? null;
        if (!is_array($definition)) {
            return '';
        }

        $settings = static::settingsMap();

        return (string) ($settings[$definition['setting_key']] ?? $definition['default'] ?? '');
    }

    private static function settingsMap(): array
    {
        if (!Schema::hasTable('settings')) {
            return [];
        }

        $keys = array_map(
            static fn (array $definition): string => (string) $definition['setting_key'],
            static::definitions()
        );

        return Setting::query()
            ->whereIn('key', $keys)
            ->orderByDesc('id')
            ->get(['key', 'value'])
            ->unique('key')
            ->pluck('value', 'key')
            ->map(static fn ($value): string => (string) $value)
            ->all();
    }

    private static function normalizeValue(string $key, mixed $value): string
    {
        return match ($key) {
            'amount' => number_format((float) $value, 2, '.', ''),
            'launch_starts_at' => Carbon::createFromFormat('Y-m-d\\TH:i', (string) $value)->format('Y-m-d H:i:s'),
            'level_one_target', 'level_two_target' => (string) max(1, (int) $value),
            default => trim((string) $value),
        };
    }

    private static function saveSettingValue(string $key, string $value): void
    {
        if (!Schema::hasTable('settings')) {
            return;
        }

        $updated = Setting::query()
            ->where('key', $key)
            ->update(['value' => $value]);

        if ($updated === 0) {
            Setting::query()->create([
                'key' => $key,
                'value' => $value,
            ]);
        }
    }
}
