<?php

namespace MediaWiki\Extension\CustomQueryPage\Store;

use MediaWiki\User\UserIdentity;
use RuntimeException;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IDatabase;
use function sprintf;
use const DB_PRIMARY;
use const DB_REPLICA;

class TagStore {
    private const TABLE = 'customquerypage_settings';
    private const KEY_ACTIVE_TAG = 'active_tag';

    private ILoadBalancer $loadBalancer;
    private string $defaultTag;
    private bool $tableStatusKnown = false;
    private bool $tableExists = false;
    private ?string $resolvedTableName = null;

    public function __construct( ILoadBalancer $loadBalancer, string $defaultTag ) {
        $this->loadBalancer = $loadBalancer;
        $this->defaultTag = $defaultTag;
    }

    public function getActiveTag(): string {
        $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
        if ( !$this->ensureTable( $dbr ) ) {
            return $this->defaultTag;
        }

        $row = $dbr->selectRow(
            self::TABLE,
            [ 'cqs_value' ],
            [ 'cqs_key' => self::KEY_ACTIVE_TAG ],
            __METHOD__
        );

        return $row ? (string)$row->cqs_value : $this->defaultTag;
    }

    public function setActiveTag( string $tag, UserIdentity $user ): void {
        $dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY );
        if ( !$this->ensureTable( $dbw ) ) {
            $tableName = $this->resolvedTableName ?? self::TABLE;
            throw new RuntimeException(
                sprintf(
                    'CustomQueryPage settings table (%s) is missing. Run maintenance/update.php.',
                    $tableName
                )
            );
        }

        $timestamp = $dbw->timestamp();
        $dbw->upsert(
            self::TABLE,
            [
                'cqs_key' => self::KEY_ACTIVE_TAG,
                'cqs_value' => $tag,
                'cqs_user' => $user->getId(),
                'cqs_timestamp' => $timestamp,
            ],
            [ 'cqs_key' ],
            [
                'cqs_value' => $tag,
                'cqs_user' => $user->getId(),
                'cqs_timestamp' => $timestamp,
            ],
            __METHOD__
        );
    }

    public function getLastUpdate(): ?array {
        $dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
        if ( !$this->ensureTable( $dbr ) ) {
            return null;
        }

        $row = $dbr->selectRow(
            self::TABLE,
            [ 'cqs_user', 'cqs_timestamp' ],
            [ 'cqs_key' => self::KEY_ACTIVE_TAG ],
            __METHOD__
        );

        if ( !$row ) {
            return null;
        }

        return [
            'user_id' => (int)$row->cqs_user,
            'timestamp' => (string)$row->cqs_timestamp,
        ];
    }

    private function ensureTable( IDatabase $db ): bool {
        if ( $this->tableStatusKnown ) {
            return $this->tableExists;
        }

        $this->resolvedTableName = $this->resolveTableName( $db );
        $this->tableExists = $db->tableExists( self::TABLE, __METHOD__ );
        $this->tableStatusKnown = true;
        return $this->tableExists;
    }

    private function resolveTableName( IDatabase $db ): string {
        if ( method_exists( $db, 'tableName' ) ) {
            return $db->tableName( self::TABLE, 'raw' );
        }

        $prefix = method_exists( $db, 'tablePrefix' ) ? $db->tablePrefix() : '';
        return $prefix . self::TABLE;
    }
}
