<?php

if (!defined('ABSPATH')) {
    exit;
}

final class TFT_Miniapp_REST_Controller
{
    private string $namespace = 'tft-miniapp/v1';

    public function register_routes(): void
    {
        register_rest_route($this->namespace, '/health', [
            'methods' => WP_REST_Server::READABLE,
            'callback' => [$this, 'health'],
            'permission_callback' => '__return_true',
        ]);
        register_rest_route($this->namespace, '/cities', [
            'methods' => WP_REST_Server::READABLE,
            'callback' => [$this, 'cities'],
            'permission_callback' => '__return_true',
        ]);
        register_rest_route($this->namespace, '/filters', [
            'methods' => WP_REST_Server::READABLE,
            'callback' => [$this, 'filters'],
            'permission_callback' => '__return_true',
            'args' => [
                'city' => [
                    'type' => 'string',
                    'enum' => ['pattaya', 'phuket'],
                ],
            ],
        ]);
        register_rest_route($this->namespace, '/tours', [
            'methods' => WP_REST_Server::READABLE,
            'callback' => [$this, 'tours'],
            'permission_callback' => '__return_true',
            'args' => $this->tour_args(),
        ]);
        register_rest_route($this->namespace, '/tours/(?P<id>[A-Za-z0-9:_-]+)', [
            'methods' => WP_REST_Server::READABLE,
            'callback' => [$this, 'tour'],
            'permission_callback' => '__return_true',
        ]);
        register_rest_route($this->namespace, '/transfers', [
            'methods' => WP_REST_Server::READABLE,
            'callback' => [$this, 'transfers'],
            'permission_callback' => '__return_true',
        ]);
        register_rest_route($this->namespace, '/transfers/(?P<id>[A-Za-z0-9:_-]+)', [
            'methods' => WP_REST_Server::READABLE,
            'callback' => [$this, 'transfer'],
            'permission_callback' => '__return_true',
        ]);
    }

    public function health(): WP_REST_Response
    {
        return $this->response([
            'ok' => true,
            'version' => TFT_MINIAPP_API_VERSION,
            'acf' => function_exists('get_fields'),
        ]);
    }

    public function cities(): WP_REST_Response
    {
        return $this->response([
            ['id' => 'pattaya', 'title' => 'Паттайя'],
            ['id' => 'phuket', 'title' => 'Пхукет'],
        ]);
    }

    public function filters(WP_REST_Request $request): WP_REST_Response
    {
        $city = sanitize_key((string) $request->get_param('city'));
        $counts = [];
        foreach ($this->load_tours() as $tour) {
            if ($city && $tour['city'] !== $city) {
                continue;
            }
            foreach ($tour['categories'] as $category) {
                $counts[$category] = ($counts[$category] ?? 0) + 1;
            }
        }

        $definitions = $city
            ? TFT_Miniapp_Normalizer::site_filter_definitions($city)
            : array_merge(
                TFT_Miniapp_Normalizer::site_filter_definitions('pattaya'),
                TFT_Miniapp_Normalizer::site_filter_definitions('phuket')
            );
        $titles = [];
        foreach ($definitions as $definition) {
            if (!isset($titles[$definition['id']])) {
                $titles[$definition['id']] = $definition['title'];
            }
        }
        $result = [];
        foreach ($titles as $id => $title) {
            $result[] = [
                'id' => $id,
                'title' => $title,
                'count' => (int) ($counts[$id] ?? 0),
            ];
        }
        return $this->response($result);
    }

    public function tours(WP_REST_Request $request): WP_REST_Response
    {
        $items = $this->load_tours();
        $city = sanitize_key((string) $request->get_param('city'));
        $search = mb_strtolower(sanitize_text_field((string) $request->get_param('search')));
        $categories = array_filter(array_map(
            'sanitize_key',
            explode(',', (string) $request->get_param('categories'))
        ));
        $featured = $request->get_param('featured');

        $items = array_values(array_filter(
            $items,
            static function (array $tour) use ($city, $search, $categories, $featured): bool {
                if ($city && $tour['city'] !== $city) {
                    return false;
                }
                if (
                    $search &&
                    !str_contains(
                        mb_strtolower($tour['title'] . ' ' . $tour['summary']),
                        $search
                    )
                ) {
                    return false;
                }
                if ($categories && !array_intersect($categories, $tour['categories'])) {
                    return false;
                }
                if ($featured !== null && $featured !== '' && (bool) $featured !== $tour['featured']) {
                    return false;
                }
                return true;
            }
        ));

        $sort = sanitize_key((string) ($request->get_param('sort') ?: 'popular'));
        usort($items, static function (array $left, array $right) use ($sort): int {
            if ($sort === 'price_asc') {
                return ($left['minAdultPrice'] ?? PHP_FLOAT_MAX) <=> ($right['minAdultPrice'] ?? PHP_FLOAT_MAX);
            }
            if ($sort === 'price_desc') {
                return ($right['minAdultPrice'] ?? -1) <=> ($left['minAdultPrice'] ?? -1);
            }
            if ($sort === 'newest') {
                return strcmp($right['updatedAt'], $left['updatedAt']);
            }
            return ($right['featured'] <=> $left['featured']) ?: strcmp($left['title'], $right['title']);
        });

        $page = max(1, (int) ($request->get_param('page') ?: 1));
        $per_page = min(100, max(1, (int) ($request->get_param('per_page') ?: 20)));
        $total = count($items);
        $page_items = array_slice($items, ($page - 1) * $per_page, $per_page);

        return $this->response([
            'data' => $page_items,
            'meta' => [
                'page' => $page,
                'perPage' => $per_page,
                'total' => $total,
                'totalPages' => max(1, (int) ceil($total / $per_page)),
            ],
        ]);
    }

    public function tour(WP_REST_Request $request)
    {
        $id = (string) $request['id'];
        foreach ($this->load_tours() as $tour) {
            if ($tour['id'] === $id || (string) $tour['wpId'] === $id) {
                return $this->response($tour);
            }
        }
        return new WP_Error('tft_tour_not_found', 'Экскурсия не найдена', ['status' => 404]);
    }

    public function transfers(WP_REST_Request $request): WP_REST_Response
    {
        $city = sanitize_key((string) $request->get_param('city'));
        $search = mb_strtolower(sanitize_text_field((string) $request->get_param('search')));
        $items = array_values(array_filter(
            $this->load_transfers(),
            static function (array $offer) use ($city, $search): bool {
                if ($city && $offer['city'] !== $city) {
                    return false;
                }
                return !$search || str_contains(
                    mb_strtolower($offer['title'] . ' ' . $offer['description']),
                    $search
                );
            }
        ));
        return $this->response([
            'data' => $items,
            'meta' => [
                'page' => 1,
                'perPage' => count($items),
                'total' => count($items),
                'totalPages' => 1,
            ],
        ]);
    }

    public function transfer(WP_REST_Request $request)
    {
        $id = (string) $request['id'];
        foreach ($this->load_transfers() as $offer) {
            if ($offer['id'] === $id) {
                return $this->response($offer);
            }
        }
        return new WP_Error('tft_transfer_not_found', 'Трансфер не найден', ['status' => 404]);
    }

    private function load_tours(): array
    {
        $cached = get_transient(TFT_MINIAPP_TOURS_CACHE_KEY);
        if (is_array($cached)) {
            return $cached;
        }

        $query = new WP_Query([
            'post_type' => tft_miniapp_tour_post_types(),
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'orderby' => [
                'menu_order' => 'ASC',
                'title' => 'ASC',
            ],
            'no_found_rows' => true,
        ]);
        $items = TFT_Miniapp_Catalog_Overrides::apply_tours(
            array_map(
                [TFT_Miniapp_Normalizer::class, 'normalize_tour'],
                $query->posts
            )
        );
        set_transient(TFT_MINIAPP_TOURS_CACHE_KEY, $items, 5 * MINUTE_IN_SECONDS);
        return $items;
    }

    private function load_transfers(): array
    {
        $cached = get_transient(TFT_MINIAPP_TRANSFERS_CACHE_KEY);
        if (is_array($cached)) {
            return $cached;
        }

        $catalog_file = TFT_MINIAPP_API_PATH . 'data/transfers.json';
        if (is_readable($catalog_file)) {
            $catalog = json_decode((string) file_get_contents($catalog_file), true);
            if (is_array($catalog) && $catalog !== []) {
                set_transient(TFT_MINIAPP_TRANSFERS_CACHE_KEY, $catalog, 5 * MINUTE_IN_SECONDS);
                return $catalog;
            }
        }

        $query = new WP_Query([
            'post_type' => 'page',
            'post_status' => 'publish',
            'posts_per_page' => -1,
            'meta_key' => '_wp_page_template',
            'meta_value' => 'template-transfer.php',
            'no_found_rows' => true,
        ]);
        $items = [];
        foreach ($query->posts as $post) {
            $items = array_merge($items, TFT_Miniapp_Normalizer::normalize_transfers($post));
        }
        set_transient(TFT_MINIAPP_TRANSFERS_CACHE_KEY, $items, 5 * MINUTE_IN_SECONDS);
        return $items;
    }

    private function response($data): WP_REST_Response
    {
        $response = new WP_REST_Response($data);
        $response->header('Cache-Control', 'public, max-age=60, stale-while-revalidate=300');
        $response->header('X-TFT-API-Version', TFT_MINIAPP_API_VERSION);
        return $response;
    }

    private function tour_args(): array
    {
        return [
            'city' => [
                'type' => 'string',
                'enum' => ['pattaya', 'phuket'],
            ],
            'categories' => [
                'type' => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ],
            'search' => [
                'type' => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ],
            'sort' => [
                'type' => 'string',
                'enum' => ['popular', 'price_asc', 'price_desc', 'newest'],
                'default' => 'popular',
            ],
            'page' => [
                'type' => 'integer',
                'minimum' => 1,
                'default' => 1,
            ],
            'per_page' => [
                'type' => 'integer',
                'minimum' => 1,
                'maximum' => 100,
                'default' => 20,
            ],
            'featured' => [
                'type' => 'boolean',
            ],
        ];
    }
}
