<?php
declare(strict_types=1);

namespace App\Models;

use DateTimeImmutable;

class Subscription extends BaseModel
{
    protected string $table = 'subscriptions';

    public function hasActive(int $subscriberId, int $creatorId, ?int $packageId = null): bool
    {
        if ($subscriberId <= 0 || $creatorId <= 0) {
            return false;
        }

        $params = [
            'subscriber_id' => $subscriberId,
            'user_id' => $subscriberId,
            'creator_id' => $creatorId,
        ];

        $scopeSql = 's.creator_id = :creator_id';
        if ($packageId !== null && $packageId > 0) {
            $scopeSql = '(' . $scopeSql . ' OR s.package_id = :package_id)';
            $params['package_id'] = $packageId;
        }

        $statement = $this->db()->prepare(
            'SELECT s.id
             FROM subscriptions s
             WHERE (s.subscriber_id = :subscriber_id OR s.user_id = :user_id)
               AND ' . $scopeSql . '
               AND s.status = "active"
               AND (s.starts_at IS NULL OR s.starts_at <= NOW())
               AND (s.ends_at IS NULL OR s.ends_at > NOW())
             LIMIT 1'
        );
        $statement->execute($params);

        return (bool) $statement->fetchColumn();
    }

    public function listForSubscriber(int $subscriberId): array
    {
        if ($subscriberId <= 0) {
            return [];
        }

        $statement = $this->db()->prepare(
            'SELECT s.*,
                    p.name AS package_name,
                    p.slug AS package_slug,
                    p.price_monthly,
                    p.price_6_month,
                    p.price_12_month,
                    p.currency,
                    u.username AS creator_username,
                    COALESCE(up.display_name, pf.display_name, u.nickname, u.username, "Creator") AS creator_name,
                    COALESCE(up.avatar, pf.avatar_path) AS creator_avatar
             FROM subscriptions s
             LEFT JOIN packages p ON p.id = s.package_id
             LEFT JOIN users u ON u.id = s.creator_id
             LEFT JOIN user_profiles up ON up.user_id = u.id
             LEFT JOIN profiles pf ON pf.user_id = u.id
             WHERE s.subscriber_id = :subscriber_id OR s.user_id = :user_id
             ORDER BY (s.status = "active" AND (s.ends_at IS NULL OR s.ends_at > NOW())) DESC, s.ends_at DESC, s.created_at DESC'
        );
        $statement->execute([
            'subscriber_id' => $subscriberId,
            'user_id' => $subscriberId,
        ]);

        return array_map(fn (array $row): array => $this->normalize($row), $statement->fetchAll());
    }

    public function listSubscribersForCreator(int $creatorId): array
    {
        if ($creatorId <= 0) {
            return [];
        }

        $statement = $this->db()->prepare(
            'SELECT s.*,
                    p.name AS package_name,
                    p.slug AS package_slug,
                    p.price_monthly,
                    p.price_6_month,
                    p.price_12_month,
                    p.currency,
                    u.username AS subscriber_username,
                    COALESCE(up.display_name, pf.display_name, u.nickname, u.username, "User") AS subscriber_name,
                    COALESCE(up.avatar, pf.avatar_path) AS subscriber_avatar
             FROM subscriptions s
             LEFT JOIN packages p ON p.id = s.package_id
             LEFT JOIN users u ON u.id = COALESCE(s.subscriber_id, s.user_id)
             LEFT JOIN user_profiles up ON up.user_id = u.id
             LEFT JOIN profiles pf ON pf.user_id = u.id
             WHERE s.creator_id = :creator_id
             ORDER BY (s.status = "active" AND (s.ends_at IS NULL OR s.ends_at > NOW())) DESC, s.created_at DESC'
        );
        $statement->execute(['creator_id' => $creatorId]);

        return array_map(fn (array $row): array => $this->normalize($row), $statement->fetchAll());
    }

    public function previewPrice(array $package, int $durationMonths): array
    {
        $durationMonths = in_array($durationMonths, [1, 6, 12], true) ? $durationMonths : 1;
        $priceKey = match ($durationMonths) {
            6 => 'price_6_month',
            12 => 'price_12_month',
            default => 'price_monthly',
        };

        $startsAt = new \DateTimeImmutable('now');
        $endsAt = $startsAt->modify('+' . $durationMonths . ' months');

        return [
            'package_id' => (int) ($package['id'] ?? 0),
            'creator_id' => (int) ($package['user_id'] ?? $package['creator_id'] ?? 0),
            'package_name' => (string) ($package['name'] ?? ''),
            'duration_months' => $durationMonths,
            'price' => round((float) ($package[$priceKey] ?? 0), 2),
            'currency' => (string) (($package['currency'] ?? '') ?: 'TRY'),
            'starts_at' => $startsAt->format('Y-m-d H:i:s'),
            'ends_at' => $endsAt->format('Y-m-d H:i:s'),
            'status' => 'pending',
            'message' => 'Odeme sistemi sonraki asamada aktif olacak. Bu onizleme gercek abonelik baslatmaz.',
        ];
    }

    public function activatePaidSubscription(int $subscriberId, int $creatorId, int $packageId, int $orderId, string $periodType): array
    {
        $months = match ($periodType) {
            '6_month' => 6,
            '12_month' => 12,
            default => 1,
        };
        $now = new DateTimeImmutable('now');

        $statement = $this->db()->prepare(
            'SELECT *
             FROM subscriptions
             WHERE (subscriber_id = :subscriber_lookup OR user_id = :user_lookup)
               AND creator_id = :creator_id
               AND package_id = :package_id
               AND status = "active"
               AND (ends_at IS NULL OR ends_at > NOW())
             ORDER BY ends_at DESC, id DESC
             LIMIT 1'
        );
        $statement->execute([
            'subscriber_lookup' => $subscriberId,
            'user_lookup' => $subscriberId,
            'creator_id' => $creatorId,
            'package_id' => $packageId,
        ]);
        $existing = $statement->fetch();

        if ($existing) {
            $base = !empty($existing['ends_at']) && strtotime((string) $existing['ends_at']) > time()
                ? new DateTimeImmutable((string) $existing['ends_at'])
                : $now;
            $endsAt = $base->modify('+' . $months . ' months');

            $update = $this->db()->prepare(
                'UPDATE subscriptions
                 SET subscriber_id = :subscriber_id,
                     user_id = :user_id,
                     order_id = :order_id,
                     ends_at = :ends_at,
                     status = "active",
                     updated_at = NOW()
                 WHERE id = :id'
            );
            $update->execute([
                'id' => (int) $existing['id'],
                'subscriber_id' => $subscriberId,
                'user_id' => $subscriberId,
                'order_id' => $orderId,
                'ends_at' => $endsAt->format('Y-m-d H:i:s'),
            ]);

            return $this->find((int) $existing['id']) ?? [];
        }

        $endsAt = $now->modify('+' . $months . ' months');
        $insert = $this->db()->prepare(
            'INSERT INTO subscriptions
                (subscriber_id, user_id, creator_id, package_id, order_id, starts_at, ends_at, status, created_at, updated_at)
             VALUES
                (:subscriber_id, :user_id, :creator_id, :package_id, :order_id, :starts_at, :ends_at, "active", NOW(), NOW())'
        );
        $insert->execute([
            'subscriber_id' => $subscriberId,
            'user_id' => $subscriberId,
            'creator_id' => $creatorId,
            'package_id' => $packageId,
            'order_id' => $orderId,
            'starts_at' => $now->format('Y-m-d H:i:s'),
            'ends_at' => $endsAt->format('Y-m-d H:i:s'),
        ]);

        return $this->find((int) $this->db()->lastInsertId()) ?? [];
    }

    public function normalize(array $row): array
    {
        $subscriberId = (int) (($row['subscriber_id'] ?? null) ?: ($row['user_id'] ?? 0));
        $creatorId = (int) ($row['creator_id'] ?? 0);
        $status = (string) (($row['status'] ?? '') ?: 'pending');
        $endsAt = (string) ($row['ends_at'] ?? '');
        $isActive = $status === 'active' && ($endsAt === '' || strtotime($endsAt) > time());

        $row['id'] = (int) ($row['id'] ?? 0);
        $row['subscriber_id'] = $subscriberId;
        $row['user_id'] = $subscriberId;
        $row['creator_id'] = $creatorId;
        $row['package_id'] = (int) ($row['package_id'] ?? 0);
        $row['order_id'] = isset($row['order_id']) && $row['order_id'] !== null ? (int) $row['order_id'] : null;
        $row['status'] = $status;
        $row['is_active'] = $isActive;
        $row['package_name'] = (string) (($row['package_name'] ?? '') ?: 'Paket');
        $row['package_slug'] = (string) ($row['package_slug'] ?? '');
        $row['creator_name'] = $row['creator_name'] ?? null;
        $row['creator_username'] = $row['creator_username'] ?? null;
        $row['creator_avatar'] = $row['creator_avatar'] ?? null;
        $row['subscriber_name'] = $row['subscriber_name'] ?? null;
        $row['subscriber_username'] = $row['subscriber_username'] ?? null;
        $row['subscriber_avatar'] = $row['subscriber_avatar'] ?? null;
        $row['price_monthly'] = round((float) ($row['price_monthly'] ?? 0), 2);
        $row['price_6_month'] = round((float) ($row['price_6_month'] ?? 0), 2);
        $row['price_12_month'] = round((float) ($row['price_12_month'] ?? 0), 2);
        $row['currency'] = (string) (($row['currency'] ?? '') ?: 'TRY');

        return $row;
    }
}
