<?php

namespace App\Support;

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

class TypingJobSettings
{
    public static function definitions(): array
    {
        return [
            'tasks_per_verified_referral' => [
                'field' => 'typing_job_tasks_per_verified_referral',
                'setting_key' => 'typing_job_tasks_per_verified_referral',
                'label' => 'Tasks Per Verified Referral',
                'type' => 'number',
                'default' => '5',
                'step' => '1',
                'min' => '1',
                'rules' => ['required', 'integer', 'min:1', 'max:9999'],
                'help' => 'আপনার referral-এ verify হওয়া প্রতি member-এর জন্য কতটি task unlock হবে।',
            ],
            'task_reward' => [
                'field' => 'typing_job_task_reward',
                'setting_key' => 'typing_job_task_reward',
                'label' => 'Task Reward Amount (BDT)',
                'type' => 'number',
                'default' => '1.00',
                'step' => '0.01',
                'min' => '0',
                'rules' => ['required', 'numeric', 'min:0', 'max:9999999.99'],
                'help' => 'প্রতি সঠিক task submit হলে user balance-এ কত টাকা যোগ হবে।',
            ],
            'launch_starts_at' => [
                'field' => 'typing_job_launch_starts_at',
                'setting_key' => 'typing_job_launch_starts_at',
                'label' => 'Start Counting From',
                'type' => 'datetime-local',
                'default' => '',
                'rules' => ['required', 'date_format:Y-m-d\\TH:i'],
                'help' => 'এই সময়ের আগে verify হওয়া referral typing job count হবে না। এখন থেকে system শুরু করতে এই cutoff use হবে।',
            ],
            'operator_mode' => [
                'field' => 'typing_job_operator_mode',
                'setting_key' => 'typing_job_operator_mode',
                'label' => 'Allowed Operator Mode',
                'type' => 'select',
                'default' => 'both',
                'options' => static::operatorModeOptions(),
                'rules' => ['required', 'in:addition,subtraction,both'],
                'help' => 'Task-এ শুধু যোগ, শুধু বিয়োগ, বা দুইটিই চালু রাখবেন।',
            ],
            'left_operand_min' => [
                'field' => 'typing_job_left_operand_min',
                'setting_key' => 'typing_job_left_operand_min',
                'label' => 'Left Operand Min',
                'type' => 'number',
                'default' => '5',
                'step' => '1',
                'min' => '0',
                'rules' => ['required', 'integer', 'min:0', 'max:99999'],
                'help' => 'অংকের বাম পাশের minimum সংখ্যা।',
            ],
            'left_operand_max' => [
                'field' => 'typing_job_left_operand_max',
                'setting_key' => 'typing_job_left_operand_max',
                'label' => 'Left Operand Max',
                'type' => 'number',
                'default' => '99',
                'step' => '1',
                'min' => '0',
                'rules' => ['required', 'integer', 'gte:typing_job_left_operand_min', 'max:99999'],
                'help' => 'অংকের বাম পাশের maximum সংখ্যা।',
            ],
            'right_operand_min' => [
                'field' => 'typing_job_right_operand_min',
                'setting_key' => 'typing_job_right_operand_min',
                'label' => 'Right Operand Min',
                'type' => 'number',
                'default' => '1',
                'step' => '1',
                'min' => '0',
                'rules' => ['required', 'integer', 'min:0', 'max:99999'],
                'help' => 'অংকের ডান পাশের minimum সংখ্যা।',
            ],
            'right_operand_max' => [
                'field' => 'typing_job_right_operand_max',
                'setting_key' => 'typing_job_right_operand_max',
                'label' => 'Right Operand Max',
                'type' => 'number',
                'default' => '49',
                'step' => '1',
                'min' => '0',
                'rules' => ['required', 'integer', 'gte:typing_job_right_operand_min', 'max:99999'],
                'help' => 'অংকের ডান পাশের maximum সংখ্যা।',
            ],
            'page_title' => [
                'field' => 'typing_job_page_title',
                'setting_key' => 'typing_job_page_title',
                'label' => 'Main Page Title',
                'type' => 'text',
                'default' => 'আপনার direct verified referral প্রতি :tasks_per_referralটি টাইপিং টাস্ক unlock হবে',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Available tokens: :tasks_per_referral, :reward',
            ],
            'page_summary' => [
                'field' => 'typing_job_page_summary',
                'setting_key' => 'typing_job_page_summary',
                'label' => 'Main Page Summary',
                'type' => 'textarea',
                'default' => 'যে account আপনার referral-এ register হয়ে verify হবে, সেই প্রতিটি verified member-এর জন্য :tasks_per_referralটি task আসবে। account owner নিজে verify হলে তার জন্য task আসবে না।',
                'rules' => ['required', 'string', 'max:1200'],
                'help' => 'Available tokens: :tasks_per_referral, :reward',
            ],
            'income_title' => [
                'field' => 'typing_job_income_title',
                'setting_key' => 'typing_job_income_title',
                'label' => 'Income Card Title',
                'type' => 'text',
                'default' => 'Typing Job Income',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'ডান পাশের income card-এর title।',
            ],
            'income_note' => [
                'field' => 'typing_job_income_note',
                'setting_key' => 'typing_job_income_note',
                'label' => 'Income Card Note',
                'type' => 'textarea',
                'default' => 'আপনি এখন পর্যন্ত টাইপিং জব থেকে যত টাকা ইনকাম করেছেন, সেটা এখানে live show হচ্ছে।',
                'rules' => ['required', 'string', 'max:1000'],
                'help' => 'Available tokens: :reward, :earned, :total_unlocked',
            ],
            'task_panel_title' => [
                'field' => 'typing_job_task_panel_title',
                'setting_key' => 'typing_job_task_panel_title',
                'label' => 'Task Panel Title',
                'type' => 'text',
                'default' => 'আজকের টাইপিং টাস্ক',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Task solve section-এর title।',
            ],
            'task_panel_summary' => [
                'field' => 'typing_job_task_panel_summary',
                'setting_key' => 'typing_job_task_panel_summary',
                'label' => 'Task Panel Summary',
                'type' => 'textarea',
                'default' => 'যে verified referral থেকে task unlock হয়েছে, সেই quota থেকে এই task চলবে। উপরের অংকের সঠিক উত্তর লিখে submit করুন।',
                'rules' => ['required', 'string', 'max:1200'],
                'help' => 'Available tokens: :tasks_per_referral, :reward',
            ],
            'answer_label' => [
                'field' => 'typing_job_answer_label',
                'setting_key' => 'typing_job_answer_label',
                'label' => 'Answer Input Label',
                'type' => 'text',
                'default' => 'সঠিক উত্তর লিখুন',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Task input box-এর label।',
            ],
            'answer_placeholder' => [
                'field' => 'typing_job_answer_placeholder',
                'setting_key' => 'typing_job_answer_placeholder',
                'label' => 'Answer Input Placeholder',
                'type' => 'text',
                'default' => 'উত্তর লিখুন',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Task input box-এর placeholder text।',
            ],
            'submit_button_label' => [
                'field' => 'typing_job_submit_button_label',
                'setting_key' => 'typing_job_submit_button_label',
                'label' => 'Submit Button Label',
                'type' => 'text',
                'default' => 'উত্তর submit করুন',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Task submit button-এর text।',
            ],
            'history_card_title' => [
                'field' => 'typing_job_history_card_title',
                'setting_key' => 'typing_job_history_card_title',
                'label' => 'Sidebar History Title',
                'type' => 'text',
                'default' => 'হিস্টোরি',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Main page-এর small history card title।',
            ],
            'history_card_summary' => [
                'field' => 'typing_job_history_card_summary',
                'setting_key' => 'typing_job_history_card_summary',
                'label' => 'Sidebar History Summary',
                'type' => 'textarea',
                'default' => 'এখানে সাম্প্রতিক সম্পন্ন task-এর ছোট summary দেখুন। full history আলাদা page-এ আছে।',
                'rules' => ['required', 'string', 'max:1000'],
                'help' => 'Small history card-এর summary text।',
            ],
            'history_link_label' => [
                'field' => 'typing_job_history_link_label',
                'setting_key' => 'typing_job_history_link_label',
                'label' => 'History Button Label',
                'type' => 'text',
                'default' => 'Full History দেখুন',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Main page থেকে history page-এ যাওয়ার button text।',
            ],
            'history_page_title' => [
                'field' => 'typing_job_history_page_title',
                'setting_key' => 'typing_job_history_page_title',
                'label' => 'History Page Title',
                'type' => 'text',
                'default' => 'আপনার সব টাইপিং জব হিস্টোরি',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Full history page-এর hero title।',
            ],
            'history_page_summary' => [
                'field' => 'typing_job_history_page_summary',
                'setting_key' => 'typing_job_history_page_summary',
                'label' => 'History Page Summary',
                'type' => 'textarea',
                'default' => 'এখানে আপনি কতগুলি task complete করেছেন, কত টাকা ইনকাম করেছেন এবং কোন অংক কবে submit করেছেন সব দেখা যাবে।',
                'rules' => ['required', 'string', 'max:1200'],
                'help' => 'Full history page-এর hero summary।',
            ],
            'history_back_label' => [
                'field' => 'typing_job_history_back_label',
                'setting_key' => 'typing_job_history_back_label',
                'label' => 'History Back Button Label',
                'type' => 'text',
                'default' => 'টাইপিং জব এ ফিরে যান',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'History page থেকে main page-এ ফেরার button text।',
            ],
            'history_empty_text' => [
                'field' => 'typing_job_history_empty_text',
                'setting_key' => 'typing_job_history_empty_text',
                'label' => 'History Empty Text',
                'type' => 'textarea',
                'default' => 'এখনো কোনো typing job history পাওয়া যায়নি।',
                'rules' => ['required', 'string', 'max:1000'],
                'help' => 'History table empty থাকলে এই text show হবে।',
            ],
            'state_table_not_ready_title' => [
                'field' => 'typing_job_state_table_not_ready_title',
                'setting_key' => 'typing_job_state_table_not_ready_title',
                'label' => 'Not Ready State Title',
                'type' => 'text',
                'default' => 'Typing Job table এখনো ready না',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'History table/migration ready না থাকলে title।',
            ],
            'state_table_not_ready_copy' => [
                'field' => 'typing_job_state_table_not_ready_copy',
                'setting_key' => 'typing_job_state_table_not_ready_copy',
                'label' => 'Not Ready State Copy',
                'type' => 'textarea',
                'default' => 'এই module-এর history table migrate হলে task submit শুরু হবে।',
                'rules' => ['required', 'string', 'max:1200'],
                'help' => 'Not ready অবস্থার description।',
            ],
            'state_no_referral_title' => [
                'field' => 'typing_job_state_no_referral_title',
                'setting_key' => 'typing_job_state_no_referral_title',
                'label' => 'No Verified Referral State Title',
                'type' => 'text',
                'default' => 'Verified referral এলে task আসবে',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Verified referral না থাকলে title।',
            ],
            'state_no_referral_copy' => [
                'field' => 'typing_job_state_no_referral_copy',
                'setting_key' => 'typing_job_state_no_referral_copy',
                'label' => 'No Verified Referral State Copy',
                'type' => 'textarea',
                'default' => 'আপনার referral-এ যুক্ত কোনো account verify হলেই আপনার এখানে :tasks_per_referralটি task unlock হবে। যে account verify করেছে, তার নিজের জন্য task আসবে না।',
                'rules' => ['required', 'string', 'max:1200'],
                'help' => 'Available tokens: :tasks_per_referral, :reward',
            ],
            'state_complete_title' => [
                'field' => 'typing_job_state_complete_title',
                'setting_key' => 'typing_job_state_complete_title',
                'label' => 'Complete State Title',
                'type' => 'text',
                'default' => 'Unlocked task সম্পন্ন হয়েছে',
                'rules' => ['required', 'string', 'max:255'],
                'help' => 'Current unlocked quota শেষ হলে title।',
            ],
            'state_complete_copy' => [
                'field' => 'typing_job_state_complete_copy',
                'setting_key' => 'typing_job_state_complete_copy',
                'label' => 'Complete State Copy',
                'type' => 'textarea',
                'default' => 'আপনার current unlocked typing task শেষ হয়েছে। নতুন verified referral এলে আরও :tasks_per_referralটি task যোগ হবে। মোট ইনকাম ৳:earned ইতোমধ্যে আপনার ব্যালেন্সে যোগ হয়েছে।',
                'rules' => ['required', 'string', 'max:1200'],
                'help' => 'Available tokens: :tasks_per_referral, :earned, :reward',
            ],
        ];
    }

    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 mechanics(): array
    {
        $leftMin = max(0, (int) static::inputValueByKey('left_operand_min'));
        $leftMax = max($leftMin, (int) static::inputValueByKey('left_operand_max'));
        $rightMin = max(0, (int) static::inputValueByKey('right_operand_min'));
        $rightMax = max($rightMin, (int) static::inputValueByKey('right_operand_max'));
        $operatorMode = static::normalizeOperatorMode(static::inputValueByKey('operator_mode'));

        return [
            'tasks_per_verified_referral' => max(1, (int) static::inputValueByKey('tasks_per_verified_referral')),
            'task_reward' => round((float) static::inputValueByKey('task_reward'), 2),
            'launch_starts_at' => static::launchStartsAt(),
            'operator_mode' => $operatorMode,
            'operators' => static::operatorsForMode($operatorMode),
            'operator_label' => static::operatorModeOptions()[$operatorMode] ?? static::operatorModeOptions()['both'],
            'left_operand_min' => $leftMin,
            'left_operand_max' => $leftMax,
            'right_operand_min' => $rightMin,
            'right_operand_max' => $rightMax,
        ];
    }

    public static function tasksPerVerifiedReferral(): int
    {
        return (int) static::mechanics()['tasks_per_verified_referral'];
    }

    public static function rewardAmount(): float
    {
        return (float) static::mechanics()['task_reward'];
    }

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

        $value = Setting::query()
            ->where('key', 'typing_job_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('typing_job_launch_starts_at', $timestamp->format('Y-m-d H:i:s'));

        return $timestamp;
    }

    public static function operatorModeOptions(): array
    {
        return [
            'both' => 'Addition + Subtraction',
            'addition' => 'Addition Only',
            'subtraction' => 'Subtraction Only',
        ];
    }

    public static function content(array $tokens = []): array
    {
        $values = static::inputValues();
        $resolvedTokens = array_merge(static::defaultTokens(), static::stringifyTokens($tokens));

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

        return $values;
    }

    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));
        }
    }

    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 defaultTokens(): array
    {
        $mechanics = static::mechanics();

        return [
            ':tasks_per_referral' => (string) $mechanics['tasks_per_verified_referral'],
            ':reward' => number_format((float) $mechanics['task_reward'], 2, '.', ''),
            ':launch_at' => $mechanics['launch_starts_at'] instanceof Carbon
                ? $mechanics['launch_starts_at']->format('d M Y, h:i A')
                : '',
            ':operator_label' => (string) $mechanics['operator_label'],
            ':left_min' => (string) $mechanics['left_operand_min'],
            ':left_max' => (string) $mechanics['left_operand_max'],
            ':right_min' => (string) $mechanics['right_operand_min'],
            ':right_max' => (string) $mechanics['right_operand_max'],
        ];
    }

    private static function stringifyTokens(array $tokens): array
    {
        $stringTokens = [];

        foreach ($tokens as $key => $value) {
            if (!is_string($key) || $key === '') {
                continue;
            }

            $stringTokens[$key] = is_scalar($value) || $value === null
                ? (string) $value
                : '';
        }

        return $stringTokens;
    }

    private static function normalizeValue(string $key, mixed $value): string
    {
        return match ($key) {
            'tasks_per_verified_referral' => (string) max(1, (int) $value),
            'task_reward' => number_format((float) $value, 2, '.', ''),
            'launch_starts_at' => Carbon::createFromFormat('Y-m-d\\TH:i', (string) $value)->format('Y-m-d H:i:s'),
            'operator_mode' => static::normalizeOperatorMode((string) $value),
            'left_operand_min', 'left_operand_max', 'right_operand_min', 'right_operand_max' => (string) max(0, (int) $value),
            default => trim((string) $value),
        };
    }

    private static function normalizeOperatorMode(string $value): string
    {
        $value = trim($value);

        return array_key_exists($value, static::operatorModeOptions()) ? $value : 'both';
    }

    /**
     * @return array<int, string>
     */
    private static function operatorsForMode(string $mode): array
    {
        return match ($mode) {
            'addition' => ['+'],
            'subtraction' => ['-'],
            default => ['+', '-'],
        };
    }

    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,
            ]);
        }
    }
}
