<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\App;
use App\Core\Database as DB;
use App\Core\RateLimiter;
use App\Core\Request;
use App\Core\Response;

/** Public read API consumed by the React frontend, plus the contact form POST. */
final class ApiController
{
    public function settings(): never
    {
        $rows = DB::select('SELECT name, value FROM settings');
        $out = [];
        foreach ($rows as $row) {
            $decoded = json_decode($row['value'], true);
            $out[$row['name']] = $decoded ?? $row['value'];
        }
        Response::json($out);
    }

    public function homepage(): never
    {
        $rows = DB::select('SELECT section, content FROM homepage_sections WHERE active = 1');
        $out = [];
        foreach ($rows as $row) {
            $out[$row['section']] = json_decode($row['content'], true);
        }
        Response::json($out);
    }

    public function treatments(): never
    {
        $rows = DB::select(
            'SELECT t.id, t.slug, t.name, t.description, t.duration, t.price, t.image,
                    t.featured, c.name AS category
             FROM treatments t
             LEFT JOIN treatment_categories c ON c.id = t.category_id
             WHERE t.status = 1 ORDER BY t.sort_order, t.id',
        );
        Response::json(array_map(fn($r) => [
            ...$r,
            'price'    => (float) $r['price'],
            'featured' => (bool) $r['featured'],
            'category' => $r['category'] ?? 'Massage',
        ], $rows));
    }

    public function packages(): never
    {
        $rows = DB::select(
            'SELECT id, slug, name, tag, dates_label, description, included, price,
                    price_label, promo_price, promo_label, image
             FROM packages WHERE active = 1 ORDER BY sort_order, id',
        );
        Response::json(array_map(fn($r) => [
            ...$r,
            'included'    => json_decode($r['included'] ?: '[]', true),
            'price'       => (float) $r['price'],
            'promo_price' => $r['promo_price'] !== null ? (float) $r['promo_price'] : null,
        ], $rows));
    }

    public function gallery(): never
    {
        $rows = DB::select(
            'SELECT i.id, i.src, i.alt, i.size, g.name AS category
             FROM gallery_images i
             LEFT JOIN gallery g ON g.id = i.gallery_id
             WHERE i.active = 1 ORDER BY i.sort_order, i.id',
        );
        Response::json(array_map(fn($r) => [...$r, 'category' => $r['category'] ?? 'Spa'], $rows));
    }

    public function testimonials(): never
    {
        Response::json(DB::select(
            'SELECT id, client_name, location, review, rating, photo, date
             FROM testimonials WHERE approved = 1 ORDER BY sort_order, date DESC',
        ));
    }

    public function team(): never
    {
        $rows = DB::select(
            'SELECT id, name, position, bio, photo, socials FROM team_members
             WHERE active = 1 ORDER BY sort_order, id',
        );
        Response::json(array_map(fn($r) => [
            ...$r,
            'socials' => json_decode($r['socials'] ?: '{}', true),
        ], $rows));
    }

    public function blog(): never
    {
        $rows = DB::select(
            "SELECT b.id, b.slug, b.title, b.excerpt, b.body, b.image, b.published_at, b.tags,
                    c.name AS category
             FROM blogs b
             LEFT JOIN blog_categories c ON c.id = b.category_id
             WHERE b.status = 'published' AND b.published_at <= ?
             ORDER BY b.published_at DESC",
            [date('Y-m-d H:i:s')],
        );
        Response::json(array_map(fn($r) => [
            ...$r,
            'category' => $r['category'] ?? 'Wellness',
            'tags'     => json_decode($r['tags'] ?: '[]', true),
        ], $rows));
    }

    public function faqs(): never
    {
        Response::json(DB::select(
            'SELECT id, question, answer FROM faqs WHERE active = 1 ORDER BY sort_order, id',
        ));
    }

    /** @param array<string, string> $params */
    public function page(Request $request, array $params): never
    {
        $page = DB::selectOne(
            'SELECT slug, title, body FROM pages WHERE slug = ? AND active = 1',
            [$params['slug']],
        );
        $page === null ? Response::error('Not found', 404) : Response::json($page);
    }

    public function contact(Request $request): never
    {
        $cfg = App::config('security')['rate_limit'];
        if (!RateLimiter::check('contact:' . $request->ip(), $cfg['max'], $cfg['window'])) {
            Response::error('Too many requests — please try again later.', 429);
        }

        $name = $request->str('name');
        $email = $request->str('email');
        $message = $request->str('message');
        $phone = $request->str('phone');

        if (mb_strlen($name) < 2 || mb_strlen($name) > 120) {
            Response::error('Please provide your name.');
        }
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            Response::error('Please provide a valid email address.');
        }
        if (mb_strlen($message) < 10 || mb_strlen($message) > 5000) {
            Response::error('Please provide a message (10–5000 characters).');
        }

        DB::insert('contacts', [
            'name'       => $name,
            'email'      => $email,
            'phone'      => mb_substr($phone, 0, 40),
            'message'    => $message,
            'ip'         => $request->ip(),
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        $mail = App::config('mail');
        if (!empty($mail['host'])) {
            // Fire-and-forget notification; failures never block the response.
            @mail(
                $mail['to'],
                'New enquiry from ' . $name,
                "From: $name <$email>\nPhone: $phone\n\n$message",
                'From: ' . $mail['from'],
            );
        }

        Response::json(['ok' => true], 201);
    }
}
