<?php
namespace app\models;

use app\app;

class subscriptions
{
    const STATES = [
        'TRIAL', 'START', 'RENEWAL',
    ];

    const STATUS = [
        'COMPLETED', 'CANCELED',
    ];

    const FREQUENCIES = [
        'minute', 'hour', 'day', 'week', 'month', 'year',
    ];

    public static function init()
    {
        app::$db->exec("CREATE TABLE IF NOT EXISTS subscriptions (
            subscription_id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id INTEGER NOT NULL REFERENCES users(id),
            product_id INTEGER NOT NULL REFERENCES products(id),
            start_date DATETIME NOT NULL,
            renews_at DATETIME NOT NULL,
            status TEXT CHECK(status IN ('" . implode("', '", self::STATUS) . "')) NOT NULL DEFAULT 'COMPLETED',
            state TEXT CHECK(state IN ('" . implode("', '", self::STATES) . "')) NOT NULL DEFAULT 'TRIAL',
            invoice_date DATETIME NOT NULL
        );");
    }

    public static function createSubscription($userId, $productId, $state, $startDate, $renewAt, $invoiceDate, $status = 'COMPLETED')
    {
        self::validateState($state);
        self::validateStatus($status);

        $stmt = app::$db->prepare("INSERT INTO subscriptions (user_id, product_id, state, status, start_date, renews_at, invoice_date)
                                   VALUES (:user_id, :product_id, :state, :status, :start_date, :renews_at, :invoice_date)");
        $stmt->execute([
            'user_id'      => $userId,
            'product_id'   => $productId,
            'state'        => $state,
            'status'       => $status,
            'start_date'   => $startDate,
            'renews_at'    => $renewAt,
            'invoice_date' => $invoiceDate,
        ]);

        return app::$db->lastInsertId();
    }

    public static function updateState(int $subscriptionId, string $state)
    {
        self::validateState($state);

        $stmt = app::$db->prepare("UPDATE subscriptions SET state = :state WHERE subscription_id = :subscription_id");
        $stmt->execute([
            'subscription_id' => $subscriptionId,
            'state'           => $state,
        ]);
    }

    public static function updateStatus(int $subscriptionId, string $status)
    {
        self::validateStatus($status);

        $stmt = app::$db->prepare("UPDATE subscriptions SET status = :status WHERE subscription_id = :subscription_id");
        $stmt->execute([
            'subscription_id' => $subscriptionId,
            'status'          => $status,
        ]);
    }

    public static function getSubscription(int $subscriptionId): array
    {
        $stmt = app::$db->prepare("SELECT * FROM subscriptions WHERE subscription_id = :subscription_id");
        $stmt->execute(['subscription_id' => $subscriptionId]);
        return $stmt->fetch() ?: [];
    }

    public static function getUserSubscriptions(int $userId): array
    {
        $stmt = app::$db->prepare("SELECT * FROM subscriptions WHERE user_id = :user_id ORDER BY start_date DESC");
        $stmt->execute(['user_id' => $userId]);
        return $stmt->fetchAll();
    }

    public static function getRecent(int $limit = 20): array
    {
        $stmt = app::$db->prepare("
            SELECT s.*, u.email as user_email, p.title as product_title,
                   p.price_cents, p.price_sats, p.subscription_frequency
            FROM subscriptions s
            LEFT JOIN users u ON s.user_id = u.id
            LEFT JOIN products p ON s.product_id = p.id
            ORDER BY s.start_date DESC
            LIMIT :limit
        ");
        $stmt->bindValue(':limit', $limit, \PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    public static function getUpcoming(int $limit = 20): array
    {
        $stmt = app::$db->prepare("
            SELECT s.*, u.email as user_email, p.title as product_title,
                   p.price_cents, p.price_sats, p.subscription_frequency
            FROM subscriptions s
            LEFT JOIN users u ON s.user_id = u.id
            LEFT JOIN products p ON s.product_id = p.id
            WHERE s.status = 'COMPLETED'
              AND s.renews_at >= datetime('now')
            ORDER BY s.renews_at ASC
            LIMIT :limit
        ");
        $stmt->bindValue(':limit', $limit, \PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    public static function getTotalRevenue(): array
    {
        $stmt = app::$db->query("
            SELECT COALESCE(SUM(p.price_cents), 0) as total_cents,
                   COALESCE(SUM(p.price_sats), 0) as total_sats,
                   COUNT(*) as total_count
            FROM subscriptions s
            LEFT JOIN products p ON s.product_id = p.id
            WHERE s.status = 'COMPLETED'
        ");
        return $stmt->fetch(\PDO::FETCH_ASSOC) ?: ['total_cents' => 0, 'total_sats' => 0, 'total_count' => 0];
    }

    public static function getActiveCount(): int
    {
        $stmt = app::$db->query("
            SELECT COUNT(*) as cnt
            FROM subscriptions
            WHERE status = 'COMPLETED'
              AND renews_at >= datetime('now')
        ");
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
        return (int) ($row['cnt'] ?? 0);
    }

    public static function getProjectedRevenue(): array
    {
        $stmt = app::$db->query("
            SELECT p.price_cents, p.price_sats, p.subscription_frequency
            FROM subscriptions s
            LEFT JOIN products p ON s.product_id = p.id
            WHERE s.status = 'COMPLETED'
              AND s.renews_at >= datetime('now')
        ");
        $active = $stmt->fetchAll(\PDO::FETCH_ASSOC);

        $projections = [
            '1mo'  => ['cents' => 0, 'sats' => 0],
            '3mo'  => ['cents' => 0, 'sats' => 0],
            '6mo'  => ['cents' => 0, 'sats' => 0],
            '1yr'  => ['cents' => 0, 'sats' => 0],
        ];

        $multipliers = [
            'minute' => ['1mo' => 43200, '3mo' => 129600, '6mo' => 259200, '1yr' => 525600],
            'hour'   => ['1mo' => 720,   '3mo' => 2160,   '6mo' => 4320,   '1yr' => 8760],
            'day'    => ['1mo' => 30,     '3mo' => 90,     '6mo' => 180,    '1yr' => 365],
            'week'   => ['1mo' => 4,      '3mo' => 13,     '6mo' => 26,     '1yr' => 52],
            'month'  => ['1mo' => 1,      '3mo' => 3,      '6mo' => 6,      '1yr' => 12],
            'year'   => ['1mo' => 0,      '3mo' => 0,      '6mo' => 0,      '1yr' => 1],
        ];

        foreach ($active as $sub) {
            $freq = $sub['subscription_frequency'] ?? 'month';
            $mults = $multipliers[$freq] ?? $multipliers['month'];

            foreach ($projections as $period => &$totals) {
                $totals['cents'] += (int) ($sub['price_cents'] ?? 0) * $mults[$period];
                $totals['sats']  += (int) ($sub['price_sats'] ?? 0) * $mults[$period];
            }
        }

        return $projections;
    }

    public static function getSubscriptionProducts(): array
    {
        $stmt = app::$db->query("
            SELECT id, title, price_cents, price_sats, subscription_frequency
            FROM products
            WHERE is_subscription = 1
              AND is_enabled = 1
            ORDER BY title
        ");
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
    }

    private static function validateState(string $state)
    {
        if (! in_array($state, self::STATES, true)) {
            throw new \InvalidArgumentException("Invalid subscription state: $state");
        }
    }

    private static function validateStatus(string $status)
    {
        if (! in_array($status, self::STATUS, true)) {
            throw new \InvalidArgumentException("Invalid subscription status: $status");
        }
    }
}
