<?php

declare(strict_types=1);

namespace App\Core;

use PDO;

/**
 * Tenant
 *
 * Answers "which company is this request for?" the same way Auth
 * answers "who is logged in?" — resolved once per request (by
 * TenantMiddleware, from the subdomain) and cached here for anything
 * downstream that needs it.
 *
 * A `business_lines` row IS a tenant now (see database migration 0018).
 * Every model that already filters by business_line_id continues to
 * work unchanged — it just now receives Tenant::id() instead of a
 * value picked from a "Homecare / Janitorial" UI toggle.
 */
final class Tenant
{
    private static ?array $current = null;
    private static bool $resolved = false;

    public static function setCurrent(?array $businessLine): void
    {
        self::$current = $businessLine;
        self::$resolved = true;
    }

    public static function current(): ?array
    {
        return self::$current;
    }

    public static function check(): bool
    {
        return self::$current !== null;
    }

    public static function id(): ?int
    {
        return self::$current !== null ? (int) self::$current['id'] : null;
    }

    public static function slug(): ?string
    {
        return self::$current['slug'] ?? null;
    }

    /** True once now() has passed subscription_expires_at with no active Stripe subscription behind it. */
    public static function isExpired(): bool
    {
        if (self::$current === null) {
            return false;
        }

        $status = self::$current['subscription_status'] ?? 'trialing';
        if ($status === 'active') {
            return false;
        }

        $expiresAt = self::$current['subscription_expires_at'] ?? null;
        $trialEndsAt = self::$current['trial_ends_at'] ?? null;
        $deadline = $expiresAt ?? $trialEndsAt;

        if ($deadline === null) {
            // No deadline set at all (e.g. manually onboarded with no
            // expiry) — treat as not expired rather than locking
            // someone out due to missing data.
            return false;
        }

        return strtotime((string) $deadline) < time();
    }

    /** Looks up a tenant by its subdomain slug. Returns null if no active row matches. */
    public static function findBySlug(string $slug): ?array
    {
        $stmt = Database::connection()->prepare(
            'SELECT * FROM business_lines WHERE slug = :slug AND is_active = 1 LIMIT 1'
        );
        $stmt->execute(['slug' => $slug]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        return $row === false ? null : $row;
    }

    /** Extracts the leftmost label of the Host header as a candidate subdomain, or null for the bare/root domain. */
    public static function subdomainFromHost(string $host, string $appDomain): ?string
    {
        $host = strtolower(explode(':', $host)[0]);
        $appDomain = strtolower($appDomain);

        if ($host === $appDomain || $host === 'www.' . $appDomain) {
            return null;
        }

        $suffix = '.' . $appDomain;
        if (!str_ends_with($host, $suffix)) {
            return null;
        }

        $sub = substr($host, 0, -strlen($suffix));

        // Reserved subdomains that are never a tenant: the platform
        // admin console and any future marketing/api hosts.
        if (in_array($sub, ['admin', 'www', 'api', 'app'], true) || $sub === '') {
            return null;
        }

        return $sub;
    }
}
