<?php

declare(strict_types=1);

namespace BeycanPress\Tokenico\Models;

use BeycanPress\Tokenico\Service;
use BeycanPress\Tokenico\Settings;
use BeycanPress\Tokenico\PluginHero\Model\AbstractModel;

class Presale extends AbstractModel
{
    /**
     * @var string
     */
    public string $tableName = 'tokenico_presale';

    /**
     * @var string
     */
    public string $version = '1.0.2';

    /**
     * Sale constructor.
     */
    public function __construct()
    {
        parent::__construct([
            'key' => [
                'type' => 'string',
                'length' => 40,
                'index' => [
                    'type' => 'unique'
                ]
            ],
            'totalSales' => [
                'type' => 'float',
                'default' => 0,
            ],
            'remainingLimit' => [
                'type' => 'float',
                'default' => 0,
            ],
            'userId' => [
                'type' => 'bigint',
            ],
            'networkId' => [
                'type' => 'string',
                'length' => 20,
            ],
            'networkCode' => [
                'type' => 'string',
                'length' => 20,
            ],
            'nativeCurrency' => [
                'type' => 'string',
                'length' => 10,
            ],
            'token' => [
                'type' => 'text'
            ],
            'data' => [
                'type' => 'text'
            ],
            'args' => [
                'type' => 'text'
            ],
            'contractAddress' => [
                'type' => 'text'
            ],
            'contractVersion' => [
                'type' => 'string',
                'length' => 5,
            ],
            'adminAddress' => [
                'type' => 'text'
            ],
            'metadata' => [
                'type' => 'text',
                'nullable' => true,
            ],
            'createdAt' => [
                'type' => 'bigint'
            ],
            'startTime' => [
                'type' => 'bigint'
            ],
            'endTime' => [
                'type' => 'bigint'
            ],
            'premium' => [
                'type' => 'boolean',
                'default' => false,
            ],
        ]);
    }

    /**
     * @param array<mixed> $filter
     * @return array<mixed>
     */
    public function filter(array $filter): array
    {
        $utcTimestamp = (int) gmdate('U');

        $limit = 12;
        $predicates = '';
        $parameters = [1];
        $offset = $filter['page'] * $limit;

        // Check if the plugin is premium
        $premium = defined('BP_TOKENICO_PRO_LOADED') ? 1 : 0;
        $predicates .= " AND premium = %d";
        $parameters[] = $premium;

        if (isset($filter['search'])) {
            $wild = '%';
            $predicates .= " AND (
                networkId LIKE %s
                OR networkCode LIKE %s
                OR nativeCurrency LIKE %s
                OR token LIKE %s
                OR metadata LIKE %s
            )";
            $like = $wild . $this->db->esc_like($filter['search']) . $wild;
            $parameters = array_merge($parameters, array_fill(0, 5, $like));
        }

        if (isset($filter['status'])) {
            if ('started' === $filter['status']) {
                $predicates .= ' AND startTime <= %d AND endTime >= %d';
                $parameters[] = $utcTimestamp;
                $parameters[] = $utcTimestamp;
            } elseif ('not-started' === $filter['status']) {
                $predicates .= ' AND startTime > %d';
                $parameters[] = $utcTimestamp;
            } elseif ('ended' === $filter['status']) {
                $predicates .= ' AND endTime < %d';
                $parameters[] = $utcTimestamp;
            }
        }

        if (isset($filter['networkId'])) {
            $predicates .= ' AND networkId = %s';
            $parameters[] = $filter['networkId'];
        } else {
            $predicates .= ' AND networkId IN ('
                . implode(',', array_fill(0, count(Settings::getNetworkIds()), '%s')) .
                ')';
            $parameters = array_merge($parameters, array_map(function ($network) {
                return "$network";
            }, Settings::getNetworkIds()));
        }

        if (isset($filter['userId'])) {
            $predicates .= ' AND userId = %d';
            $parameters[] = $filter['userId'];
        }

        $searchSql = 'SELECT * FROM ' . $this->tableName .
            ' WHERE %d' . $predicates .
            ' ORDER BY id DESC LIMIT %d OFFSET %d';
        $totalCountSql = 'SELECT COUNT(*) FROM ' . $this->tableName . ' WHERE %d' . $predicates;

        $records = $this->getResults($this->prepare($searchSql, array_merge($parameters, [$limit, $offset])));

        $totalCount = (int) $this->getVar($this->prepare($totalCountSql, $parameters));

        $totalPage = (int) ceil($totalCount / $limit);

        return [
            Service::presaleBulkFormat($records),
            $totalPage
        ];
    }
}
