<?php

declare(strict_types=1);

namespace Bot\Infrastructure\Repository\Database;

use Bot\Domain\Entity\ForcedJoinChannel;
use Bot\Domain\Repository\ForcedJoinChannelRepositoryInterface;
use PDO;

final class DatabaseForcedJoinChannelRepository implements ForcedJoinChannelRepositoryInterface
{
    public function __construct(
        private readonly PDO $pdo,
    ) {
    }

    /**
     * @return ForcedJoinChannel[]
     */
    public function findAll(): array
    {
        $stmt = $this->pdo->prepare('SELECT * FROM forced_join_channels ORDER BY id DESC');
        $stmt->execute();
        $rows = $stmt->fetchAll();

        $channels = [];
        foreach ($rows as $row) {
            $channels[] = $this->rowToChannel($row);
        }

        return $channels;
    }

    /**
     * @return ForcedJoinChannel[]
     */
    public function findEnabled(): array
    {
        $stmt = $this->pdo->prepare('SELECT * FROM forced_join_channels WHERE enabled = 1 ORDER BY id DESC');
        $stmt->execute();
        $rows = $stmt->fetchAll();

        $channels = [];
        foreach ($rows as $row) {
            $channels[] = $this->rowToChannel($row);
        }

        return $channels;
    }

    public function findByChannelUsername(string $channelUsername): ?ForcedJoinChannel
    {
        $stmt = $this->pdo->prepare('SELECT * FROM forced_join_channels WHERE channel_username = :channel_username');
        $stmt->execute(['channel_username' => $channelUsername]);
        $row = $stmt->fetch();

        if ($row === false) {
            return null;
        }

        return $this->rowToChannel($row);
    }

    public function findById(int $id): ?ForcedJoinChannel
    {
        $stmt = $this->pdo->prepare('SELECT * FROM forced_join_channels WHERE id = :id');
        $stmt->execute(['id' => $id]);
        $row = $stmt->fetch();

        if ($row === false) {
            return null;
        }

        return $this->rowToChannel($row);
    }

    public function save(ForcedJoinChannel $channel): void
    {
        $id = $channel->getId();

        if ($id === 0) {
            // Insert
            $stmt = $this->pdo->prepare(
                'INSERT INTO forced_join_channels (channel_username, channel_type, enabled, invite_link)
                 VALUES (:channel_username, :channel_type, :enabled, :invite_link)'
            );
            $stmt->execute([
                'channel_username' => $channel->getChannelUsername(),
                'channel_type' => $channel->getChannelType(),
                'enabled' => $channel->isEnabled() ? 1 : 0,
                'invite_link' => $channel->getInviteLink(),
            ]);
        } else {
            // Update
            $stmt = $this->pdo->prepare(
                'UPDATE forced_join_channels SET
                    channel_username = :channel_username,
                    channel_type = :channel_type,
                    enabled = :enabled,
                    invite_link = :invite_link
                WHERE id = :id'
            );
            $stmt->execute([
                'id' => $id,
                'channel_username' => $channel->getChannelUsername(),
                'channel_type' => $channel->getChannelType(),
                'enabled' => $channel->isEnabled() ? 1 : 0,
                'invite_link' => $channel->getInviteLink(),
            ]);
        }
    }

    public function delete(int $id): void
    {
        $stmt = $this->pdo->prepare('DELETE FROM forced_join_channels WHERE id = :id');
        $stmt->execute(['id' => $id]);
    }

    /**
     * @param array<string,mixed> $row
     */
    private function rowToChannel(array $row): ForcedJoinChannel
    {
        $channel = new ForcedJoinChannel(
            (int) $row['id'],
            $row['channel_username'],
            $row['channel_type'],
            (bool) ($row['enabled'] ?? true),
            $row['invite_link'] ?? null,
        );

        return $channel;
    }
}

