<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\AutomationRule;
use App\Models\CrmMessage;
use App\Models\CrmSetting;
use App\Models\Exam;
use App\Models\ExamMark;
use App\Models\MessageCampaign;
use App\Models\MessageTemplate;
use App\Models\Student;
use App\Services\WhatsAppService;
use Illuminate\Http\Request;

class CrmController extends Controller
{
    public function __construct(private WhatsAppService $wa)
    {
    }

    /* ── Overview ─────────────────────────────────────────────────── */

    public function overview()
    {
        return response()->json([
            'total' => CrmMessage::count(),
            'sent' => CrmMessage::where('status', 'sent')->count(),
            'ready' => CrmMessage::where('status', 'ready')->count(),
            'failed' => CrmMessage::where('status', 'failed')->count(),
            'skipped' => CrmMessage::where('status', 'skipped')->count(),
            'campaigns' => MessageCampaign::count(),
            'mode' => CrmSetting::current()->mode,
        ]);
    }

    /* ── Templates ────────────────────────────────────────────────── */

    public function templates()
    {
        return response()->json(['data' => MessageTemplate::orderBy('category')->orderBy('name')->get()]);
    }

    public function storeTemplate(Request $request)
    {
        $data = $request->validate([
            'name' => ['required', 'string'],
            'category' => ['nullable', 'string'],
            'body_en' => ['nullable', 'string'],
            'body_fa' => ['nullable', 'string'],
            'body_ps' => ['nullable', 'string'],
            'active' => ['nullable', 'boolean'],
        ]);

        return response()->json(MessageTemplate::create($data), 201);
    }

    public function updateTemplate(Request $request, MessageTemplate $template)
    {
        $template->update($request->only(['name', 'category', 'body_en', 'body_fa', 'body_ps', 'active']));

        return response()->json($template);
    }

    public function destroyTemplate(MessageTemplate $template)
    {
        $template->delete();

        return response()->json(['ok' => true]);
    }

    /* ── Settings ─────────────────────────────────────────────────── */

    public function settings(Request $request)
    {
        $s = CrmSetting::current();

        return response()->json(array_merge($s->toArray(), [
            'has_token' => (bool) $s->access_token,
            // Point this at Meta's webhook config to receive delivery receipts.
            'webhook_url' => url('/api/crm/webhook'),
        ]));
    }

    public function updateSettings(Request $request)
    {
        $s = CrmSetting::current();
        $data = $request->validate([
            'mode' => ['nullable', 'in:manual,cloud_api'],
            'phone_number_id' => ['nullable', 'string'],
            'business_account_id' => ['nullable', 'string'],
            'access_token' => ['nullable', 'string'],
            'verify_token' => ['nullable', 'string'],
            'use_templates' => ['nullable', 'boolean'],
            'template_name' => ['nullable', 'string'],
            'template_lang' => ['nullable', 'string'],
            'country_code' => ['nullable', 'string'],
            'sender_name' => ['nullable', 'string'],
            'default_language' => ['nullable', 'in:en,fa,ps'],
        ]);
        // Never blank an existing token unless a new one is supplied.
        if (empty($data['access_token'])) {
            unset($data['access_token']);
        }
        $s->update($data);

        return $this->settings($request);
    }

    // Validate the Cloud API credentials against Meta's Graph API.
    public function testConnection()
    {
        return response()->json($this->wa->testConnection());
    }

    /* ── Meta webhook (public) ────────────────────────────────────── */

    // GET handshake — Meta verifies the endpoint once when you subscribe.
    public function webhookVerify(Request $request)
    {
        $verify = CrmSetting::current()->verify_token;
        if ($request->query('hub_mode') === 'subscribe'
            && $verify
            && hash_equals($verify, (string) $request->query('hub_verify_token'))) {
            return response($request->query('hub_challenge'), 200)->header('Content-Type', 'text/plain');
        }

        return response('Forbidden', 403);
    }

    // POST callbacks — delivery/read receipts and inbound parent replies.
    public function webhookReceive(Request $request)
    {
        foreach ($request->input('entry', []) as $entry) {
            foreach ($entry['changes'] ?? [] as $change) {
                $value = $change['value'] ?? [];

                foreach ($value['statuses'] ?? [] as $status) {
                    $this->wa->applyStatus(
                        $status['id'] ?? '',
                        $status['status'] ?? '',
                        $status['errors'][0]['title'] ?? null,
                    );
                }

                foreach ($value['messages'] ?? [] as $inbound) {
                    $this->recordInbound($inbound);
                }
            }
        }

        // Meta only needs a fast 200; anything else triggers retries.
        return response()->json(['received' => true]);
    }

    private function recordInbound(array $inbound): void
    {
        $phone = '+'.preg_replace('/\D/', '', $inbound['from'] ?? '');
        $student = Student::where('father_mobile', 'like', '%'.substr($phone, -9))
            ->orWhere('guardian_mobile', 'like', '%'.substr($phone, -9))
            ->orWhere('mother_mobile', 'like', '%'.substr($phone, -9))
            ->first();

        CrmMessage::create([
            'rule_key' => 'inbound',
            'recipient_type' => 'parent',
            'recipient_id' => $student?->id,
            'recipient_name' => $student ? trim($student->first_name.' '.$student->last_name) : ($inbound['from'] ?? 'Unknown'),
            'phone' => $phone,
            'body' => $inbound['text']['body'] ?? '['.($inbound['type'] ?? 'media').']',
            'wa_message_id' => $inbound['id'] ?? null,
            'status' => 'received',
        ]);
    }

    /* ── Automations ──────────────────────────────────────────────── */

    public function automations()
    {
        return response()->json(['data' => AutomationRule::with('template:id,name')->orderBy('id')->get()]);
    }

    public function updateAutomation(Request $request, AutomationRule $rule)
    {
        $rule->update($request->only(['enabled', 'template_id', 'params']));

        return response()->json($rule->fresh('template'));
    }

    public function runAutomations()
    {
        return response()->json(['queued' => $this->wa->runAutomations()]);
    }

    /* ── Campaigns / compose ──────────────────────────────────────── */

    public function campaigns()
    {
        return response()->json(['data' => MessageCampaign::with('template:id,name')->orderByDesc('id')->limit(200)->get()]);
    }

    // Resolve an audience and (optionally) preview without sending.
    public function previewAudience(Request $request)
    {
        $recipients = $this->wa->resolveAudience($request->input('audience', []));
        $body = $this->resolveBody($request);
        $first = $recipients[0] ?? null;

        return response()->json([
            'count' => count($recipients),
            'no_phone' => count(array_filter($recipients, fn ($r) => empty($r['phone']))),
            'sample' => $first ? [
                'name' => $first['name'],
                'phone' => $this->wa->normalizePhone($first['phone']),
                'body' => $body ? $this->wa->render($body, $first) : '',
            ] : null,
        ]);
    }

    public function sendCampaign(Request $request)
    {
        $data = $request->validate([
            'title' => ['required', 'string'],
            'template_id' => ['nullable', 'exists:message_templates,id'],
            'body' => ['nullable', 'string'],
            'language' => ['nullable', 'in:en,fa,ps'],
            'audience' => ['required', 'array'],
        ]);
        $body = $this->resolveBody($request);
        if (!$body) {
            return response()->json(['message' => 'A template or a custom message body is required.'], 422);
        }

        $recipients = $this->wa->resolveAudience($data['audience']);
        $campaign = MessageCampaign::create([
            'title' => $data['title'],
            'template_id' => $data['template_id'] ?? null,
            'body' => $data['body'] ?? null,
            'audience' => $data['audience'],
            'language' => $data['language'] ?? 'fa',
            'status' => 'queued',
            'total' => count($recipients),
            'created_by' => $request->user()?->name,
        ]);

        foreach ($recipients as $r) {
            $this->wa->queue($r, $this->wa->render($body, $r), $campaign->id);
        }

        $campaign->update([
            'status' => 'sent',
            'sent_at' => now(),
            'sent_count' => $campaign->messages()->whereIn('status', ['sent', 'ready'])->count(),
            'failed_count' => $campaign->messages()->whereIn('status', ['failed', 'skipped'])->count(),
        ]);

        return response()->json($campaign->fresh(), 201);
    }

    // One-click blasts for exam results and monthly report cards.
    public function sendExamResults(Request $request)
    {
        $data = $request->validate(['exam_id' => ['required', 'exists:exams,id']]);
        $exam = Exam::findOrFail($data['exam_id']);
        $lang = CrmSetting::current()->default_language ?: 'fa';
        $template = MessageTemplate::where('key', 'exam_results')->first();
        $body = $template?->composed();
        if (!$body) {
            return response()->json(['message' => 'exam_results template missing'], 422);
        }

        $marks = ExamMark::where('exam_id', $exam->id)->get()->groupBy('student_id');
        $n = 0;
        foreach ($marks as $studentId => $rows) {
            $student = Student::with('schoolClass')->find($studentId);
            if (!$student) {
                continue;
            }
            $obtained = $rows->sum('marks');
            $total = $rows->sum('max_marks');
            $r = $this->wa->parentRecipient($student);
            $rendered = $this->wa->render($body, $r, [
                'exam_name' => $exam->name,
                'obtained' => $obtained,
                'total' => $total,
                'percentage' => $total ? round($obtained / $total * 100) : 0,
            ]);
            $n += $this->wa->queue($r, $rendered, null, 'exam_results', "exam_results|{$exam->id}|{$studentId}") ? 1 : 0;
        }

        return response()->json(['queued' => $n]);
    }

    public function sendMonthlyReports(Request $request)
    {
        $lang = CrmSetting::current()->default_language ?: 'fa';
        $rule = AutomationRule::where('key', 'monthly_report')->first();
        $body = $rule?->template?->composed();
        if (!$body) {
            return response()->json(['message' => 'monthly_report template missing'], 422);
        }
        $n = $this->wa->queueMonthlyReports($rule, $body, $request->integer('class_id') ?: null);

        return response()->json(['queued' => $n]);
    }

    /* ── Message log ──────────────────────────────────────────────── */

    public function messages(Request $request)
    {
        $rows = CrmMessage::query()
            ->when($request->query('status'), fn ($q, $s) => $q->where('status', $s))
            ->when($request->query('campaign_id'), fn ($q, $c) => $q->where('campaign_id', $c))
            ->when($request->query('rule_key'), fn ($q, $r) => $q->where('rule_key', $r))
            ->orderByDesc('id')
            ->limit((int) ($request->query('limit') ?: 500))
            ->get();

        return response()->json(['data' => $rows]);
    }

    public function retryMessage(CrmMessage $message)
    {
        $message->update(['status' => 'queued', 'error' => null]);
        $this->wa->send($message);

        return response()->json($message->fresh());
    }

    // Manual mode: operator confirms they delivered the wa.me message.
    public function markSent(CrmMessage $message)
    {
        $message->update(['status' => 'sent', 'sent_at' => now()]);

        return response()->json($message);
    }

    public function destroyMessage(CrmMessage $message)
    {
        $message->delete();

        return response()->json(['ok' => true]);
    }

    private function resolveBody(Request $request): ?string
    {
        if ($request->filled('body')) {
            return $request->input('body');
        }
        if ($request->filled('template_id')) {
            $template = MessageTemplate::find($request->input('template_id'));

            return $template?->bodyFor($request->input('language', 'fa'));
        }

        return null;
    }
}
