<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\AlertRule;
use App\Models\CaseOption;
use App\Models\Client;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Spatie\Permission\Models\Role;

class ReportRuleController extends Controller
{
    public function index(Request $request)
    {
        abort_unless($request->user()->can('rules.manage'), 403);

        $rules = AlertRule::query()->with('client')->orderByDesc('id')->paginate(20);

        return view('admin.report-rules.index', [
            'rules' => $rules,
        ]);
    }

    public function create(Request $request)
    {
        abort_unless($request->user()->can('rules.manage'), 403);

        return view('admin.report-rules.create', [
            'clients' => Client::query()->orderBy('name')->get(),
            'statuses' => CaseOption::query()->where('group', 'status')->where('is_active', true)->orderBy('sort_order')->pluck('value')->all(),
            'actions' => CaseOption::query()->where('group', 'action_social')->where('is_active', true)->orderBy('sort_order')->pluck('value')->all(),
            'roles' => Role::query()->orderBy('name')->pluck('name')->all(),
            'emailOptions' => $this->emailOptions(),
            'blockOptions' => $this->blockOptions(),
        ]);
    }

    public function store(Request $request)
    {
        abort_unless($request->user()->can('rules.manage'), 403);

        $data = $this->validatePayload($request);

        $rule = AlertRule::create($data);

        return redirect()->route('admin.report-rules.edit', $rule)->with('status', 'Report rule created.');
    }

    public function edit(Request $request, AlertRule $report_rule)
    {
        abort_unless($request->user()->can('rules.manage'), 403);

        return view('admin.report-rules.edit', [
            'rule' => $report_rule,
            'clients' => Client::query()->orderBy('name')->get(),
            'statuses' => CaseOption::query()->where('group', 'status')->where('is_active', true)->orderBy('sort_order')->pluck('value')->all(),
            'actions' => CaseOption::query()->where('group', 'action_social')->where('is_active', true)->orderBy('sort_order')->pluck('value')->all(),
            'roles' => Role::query()->orderBy('name')->pluck('name')->all(),
            'emailOptions' => $this->emailOptions(),
            'blockOptions' => $this->blockOptions(),
        ]);
    }

    public function update(Request $request, AlertRule $report_rule)
    {
        abort_unless($request->user()->can('rules.manage'), 403);

        $data = $this->validatePayload($request);

        $report_rule->update($data);

        return redirect()->route('admin.report-rules.edit', $report_rule)->with('status', 'Report rule updated.');
    }

    public function destroy(Request $request, AlertRule $report_rule)
    {
        abort_unless($request->user()->can('rules.manage'), 403);

        $report_rule->delete();

        return redirect()->route('admin.report-rules.index')->with('status', 'Report rule deleted.');
    }

    public function runNow(Request $request, AlertRule $report_rule)
    {
        abort_unless($request->user()->can('rules.manage'), 403);

        Artisan::call('reports:send-alerts', [
            '--rule_id' => $report_rule->id,
            '--force' => true,
            '--manual' => true,
        ]);

        return back()->with('status', 'Report rule executed manually.');
    }

    private function validatePayload(Request $request): array
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'is_global' => ['nullable', 'boolean'],
            'client_id' => ['nullable', 'integer', 'exists:clients,id'],
            'enabled' => ['nullable', 'boolean'],
            'statuses' => ['required', 'array', 'min:1'],
            'statuses.*' => ['required', 'string'],
            'trigger_actions' => ['nullable', 'array'],
            'trigger_actions.*' => ['string'],
            'check_every_minutes' => ['required', 'integer', 'min:5', 'max:1440'],
            'recipients_roles' => ['nullable', 'array'],
            'recipients_roles.*' => ['string'],
            'recipients_emails' => ['nullable', 'string'],
            'recipients_emails_selected' => ['nullable', 'array'],
            'recipients_emails_selected.*' => ['email'],
            'cc_client' => ['nullable', 'boolean'],
            'email_subject' => ['required', 'string', 'max:255'],
            'email_body' => ['required', 'string'],
            'renotify_every_hours' => ['nullable', 'integer', 'min:1', 'max:720'],
            'track_date_from' => ['nullable', 'date'],
            'track_date_to' => ['nullable', 'date', 'after_or_equal:track_date_from'],
            'report_blocks_json' => ['nullable', 'string'],
        ]);

        $isGlobal = (bool) ($data['is_global'] ?? false);
        if ($isGlobal) {
            $data['client_id'] = null;
        }

        $manualEmails = collect(explode(',', (string) ($data['recipients_emails'] ?? '')))
            ->map(fn ($v) => trim($v))
            ->filter()
            ->all();

        $selectedEmails = collect($data['recipients_emails_selected'] ?? [])
            ->map(fn ($v) => trim((string) $v))
            ->filter()
            ->all();

        $emails = array_values(array_unique(array_merge($selectedEmails, $manualEmails)));

        $data['is_global'] = $isGlobal;
        $data['enabled'] = (bool) ($data['enabled'] ?? false);
        $data['cc_client'] = (bool) ($data['cc_client'] ?? false);
        $data['recipients_roles'] = $data['recipients_roles'] ?? [];
        $data['trigger_actions'] = $data['trigger_actions'] ?? [];
        $data['recipients_emails'] = $emails;
        $data['report_blocks'] = $this->normalizeBlocks($data['report_blocks_json'] ?? null);
        unset($data['recipients_emails_selected']);
        unset($data['report_blocks_json']);

        return $data;
    }

    private function emailOptions(): array
    {
        $userEmails = User::query()
            ->whereNotNull('email')
            ->pluck('email')
            ->all();

        $clientEmails = Client::query()
            ->pluck('default_notification_emails')
            ->flatten()
            ->filter()
            ->all();

        $all = array_values(array_unique(array_merge($userEmails, $clientEmails)));
        sort($all);

        return $all;
    }

    private function blockOptions(): array
    {
        return [
            'custom_message' => 'Custom Message (Email Body Template)',
            'client_info' => 'Client Info',
            'summary_kpis' => 'Summary KPIs',
            'status_breakdown' => 'Status Breakdown',
            'sentiment_breakdown' => 'Sentiment Breakdown',
            'open_cases_table' => 'Open Cases Table',
            'closed_cases_table' => 'Closed Cases Table',
            'critical_cases_table' => 'Critical Cases Table',
        ];
    }

    private function normalizeBlocks(?string $json): array
    {
        $allowed = array_keys($this->blockOptions());
        $default = ['custom_message', 'summary_kpis', 'open_cases_table', 'closed_cases_table'];
        if (!$json) {
            return $default;
        }

        $decoded = json_decode($json, true);
        if (!is_array($decoded)) {
            return $default;
        }

        $blocks = array_values(array_filter($decoded, fn ($v) => in_array($v, $allowed, true)));

        $blocks = count($blocks) > 0 ? array_values(array_unique($blocks)) : $default;

        // Best-practice fallback: always include custom message block so template content is never dropped.
        if (!in_array('custom_message', $blocks, true)) {
            array_unshift($blocks, 'custom_message');
        }

        return $blocks;
    }
}
