<?php

namespace App\Filters;

use App\Models\Control\TenantRecordModel;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Tenancy as TenancyConfig;

/**
 * Resolves which hotel (tenant) the current request belongs to, BEFORE any
 * tenant-scoped model runs, and stashes it on the shared TenantContext
 * service so the rest of the request just works.
 *
 * Resolution order:
 *   1. Subdomain, e.g. "demo" from demo.maxyields.test — the production path.
 *   2. Session — set by the dev tenant switcher (see TenantSwitchController),
 *      so a developer can flip between seeded hotels without real subdomains.
 *   3. tenant.defaultSlug from .env — convenience for a single-hotel local
 *      setup where nobody wants to fuss with hosts files.
 *
 * If none of those resolve to an active tenant, the request is stopped with
 * a plain "unknown hotel" page rather than falling through to a controller
 * that would otherwise hit a database that doesn't exist.
 */
class TenantResolver implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        $config = config(TenancyConfig::class);
        $slug   = $this->resolveSlug($request, $config);

        if ($slug === null) {
            return $this->unknownTenantResponse('No hotel selected for this request.');
        }

        $tenants = new TenantRecordModel();
        $tenant  = $tenants->findActiveBySlug($slug);

        if ($tenant === null) {
            return $this->unknownTenantResponse("No active hotel found for \"{$slug}\".");
        }

        service('tenantContext')->setTenant($tenant);

        return null;
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
        // Nothing to do — connections are request-scoped and torn down naturally.
    }

    private function resolveSlug(RequestInterface $request, TenancyConfig $config): ?string
    {
        $host   = $request->getServer('HTTP_HOST') ?? '';
        $host   = explode(':', $host)[0]; // strip port for local dev, e.g. "demo.localhost:8080"
        $labels = explode('.', $host);

        if (count($labels) > 1 && ! in_array($host, $config->nonTenantHosts, true)) {
            $candidate = $labels[0];

            if ($candidate !== '' && ! in_array($candidate, ['www'], true)) {
                return $candidate;
            }
        }

        $session = session();

        if ($session->has('dev_tenant_slug')) {
            return $session->get('dev_tenant_slug');
        }

        return $config->defaultSlug;
    }

    private function unknownTenantResponse(string $message)
    {
        $response = service('response');

        return $response
            ->setStatusCode(404)
            ->setBody(view('errors/unknown_tenant', ['message' => $message]));
    }
}
