<?php
declare(strict_types=1);

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Request;
use App\Core\Validator;
use App\Models\AuditLog;
use App\Models\Campaign;
use App\Models\CampaignRecipient;
use App\Models\EmailTemplate;
use App\Models\MarketingList;
use App\Services\CampaignSender;
use App\Services\MergeService;

final class CampaignController extends BaseController
{
    public function index(Request $request): void
    {
        $this->requireModule('campaigns');
        $page = $this->page();
        $status = (string) ($_GET['status'] ?? 'all');
        if (!in_array($status, ['all', 'sent', 'draft'], true)) {
            $status = 'all';
        }
        $result = Campaign::paginate($page, 15, $status);
        $rows = array_map(static function (array $c): array {
            $c['stats'] = Campaign::stats((int) $c['id']);
            return $c;
        }, $result['rows']);
        view('marketing/campaigns', [
            'title' => 'Campaigns',
            'rows' => $rows,
            'total' => $result['total'],
            'page' => $page,
            'pages' => max(1, (int) ceil($result['total'] / 15)),
            'status' => $status,
            'counts' => Campaign::boardCounts(),
            'templates' => EmailTemplate::allActive(),
            'lists' => MarketingList::allActive(),
            'summary' => Campaign::monthSummary(),
            'notifications' => $this->notifications(),
        ]);
    }

    public function show(Request $request): void
    {
        $this->requireModule('campaigns');
        $id = (int) $request->param('id');
        $row = Campaign::detail($id);
        if (!$row) {
            flash('error', 'Campaign not found.');
            redirect('campaigns');
        }
        view('marketing/campaign_show', [
            'title' => $row['name'],
            'campaign' => $row,
            'stats' => Campaign::stats($id),
            'notifications' => $this->notifications(),
        ]);
    }

    public function store(Request $request): void
    {
        $this->requireModule('campaigns');
        $this->verifyCsrf($request);
        $data = $request->all();
        $v = (new Validator())->required($data, ['name' => 'Name', 'subject' => 'Subject', 'body' => 'Body', 'list_id' => 'List']);
        if ($v->fails()) {
            $this->fail($v);
        }
        $list = MarketingList::find((int) $data['list_id']);
        if (!$list) {
            json_out(['ok' => false, 'error' => 'Pick a saved list.'], 422);
        }
        $templateId = !empty($data['template_id']) ? (int) $data['template_id'] : null;
        if ($templateId && !EmailTemplate::find($templateId)) {
            $templateId = null;
        }
        $id = Campaign::create([
            'name' => mb_substr((string) $data['name'], 0, 180),
            'template_id' => $templateId,
            'list_id' => (int) $list['id'],
            'subject' => mb_substr((string) $data['subject'], 0, 180),
            'body' => MergeService::sanitizeBody((string) $data['body']),
            'status' => 'draft',
            'created_by' => Auth::instance()->id(),
        ]);
        AuditLog::write('campaign.create', 'campaign', $id);
        json_out(['ok' => true, 'id' => $id, 'redirect' => url('campaigns/' . $id)]);
    }

    public function send(Request $request): void
    {
        $this->requireModule('campaigns');
        $this->verifyCsrf($request);
        $id = (int) $request->param('id');
        try {
            $result = CampaignSender::send($id);
        } catch (\RuntimeException $e) {
            json_out(['ok' => false, 'error' => $e->getMessage()], 422);
        }
        json_out(['ok' => true, 'message' => $result['sent'] . ' emails logged on customer records.']);
    }

    public function reports(Request $request): void
    {
        $this->requireModule('campaign_reports');
        $page = $this->page();
        $status = (string) ($_GET['status'] ?? 'sent');
        if (!in_array($status, ['all', 'sent', 'draft'], true)) {
            $status = 'sent';
        }
        $result = Campaign::paginate($page, 20, $status);
        $bounces = CampaignRecipient::bounces(1, 20);
        view('marketing/reports', [
            'title' => 'Campaign reports',
            'rows' => $result['rows'],
            'stats' => array_map(static function (array $c): array {
                $c['stats'] = Campaign::stats((int) $c['id']);
                return $c;
            }, $result['rows']),
            'summary' => Campaign::monthSummary(),
            'counts' => Campaign::boardCounts(),
            'status' => $status,
            'bounces' => $bounces['rows'],
            'page' => $page,
            'pages' => max(1, (int) ceil($result['total'] / 20)),
            'notifications' => $this->notifications(),
        ]);
    }

    public function bounce(Request $request): void
    {
        $this->requireModule('campaigns');
        $this->verifyCsrf($request);
        $id = (int) $request->param('id');
        CampaignRecipient::markBounce($id);
        json_out(['ok' => true, 'message' => 'Marked as bounced. That address will not be emailed again.']);
    }
}
