<?php

declare(strict_types=1);

namespace Plugin\tnt_international_phone\src\Admin;

use JTL\DB\DbInterface;
use JTL\Plugin\PluginInterface;
use JTL\Smarty\JTLSmarty;
use Plugin\tnt_international_phone\src\Service\InvalidPhoneLogger;
use Plugin\tnt_international_phone\src\Service\ModifiedPhoneLogger;
use stdClass;

/**
 * Admin audit report: recent invalid phone submissions with counts and CSV export.
 *
 * Instantiated from adminmenu/report.php (Customlink file) — resolved by file name,
 * NOT by the (gettext-translated) admin-menu cName, so translation cannot break it.
 */
final class InvalidPhoneReport
{
    private const RECENT_LIMIT = 100;

    public function __construct(private readonly DbInterface $db)
    {
    }

    public function render(PluginInterface $plugin, JTLSmarty $smarty): string
    {
        $table          = InvalidPhoneLogger::TABLE;
        $recent         = $this->db->getObjects(
            'SELECT id, form, field, raw_value, country_hint, reason, created_at
                FROM ' . $table . '
                ORDER BY id DESC
                LIMIT ' . self::RECENT_LIMIT
        );
        $modified       = $this->db->getObjects(
            'SELECT id, form, field, before_value, after_value, country_hint, created_at
                FROM ' . ModifiedPhoneLogger::TABLE . '
                ORDER BY id DESC
                LIMIT ' . self::RECENT_LIMIT
        );
        $counts         = $this->buildCounts();
        $modifiedCounts = $this->buildModifiedCounts();
        $backendURL     = $plugin->getPaths()->getBackendURL();
        $csvURL         = $backendURL . '?tnt_ip_export_csv=1';
        $modifiedCsvURL = $backendURL . '?tnt_ip_export_modified_csv=1';

        return $smarty->assign('tntIpRecent', $recent)
            ->assign('tntIpCounts', $counts)
            ->assign('tntIpCsvURL', $csvURL)
            ->assign('tntIpLimit', self::RECENT_LIMIT)
            ->assign('tntIpModified', $modified)
            ->assign('tntIpModifiedCounts', $modifiedCounts)
            ->assign('tntIpModifiedCsvURL', $modifiedCsvURL)
            ->fetch(rtrim($plugin->getPaths()->getAdminPath(), '/') . '/templates/report.tpl');
    }

    /**
     * Aggregated counters for the audit report.
     *
     * @return array{total: int, last7: int, byForm: array<stdClass>, byReason: array<stdClass>}
     */
    public function buildCounts(): array
    {
        $table = InvalidPhoneLogger::TABLE;

        return [
            'total'  => $this->db->getSingleInt('SELECT COUNT(*) AS cnt FROM ' . $table, 'cnt'),
            'last7'  => $this->db->getSingleInt(
                'SELECT COUNT(*) AS cnt FROM ' . $table
                . ' WHERE created_at >= NOW() - INTERVAL 7 DAY',
                'cnt'
            ),
            'byForm' => $this->db->getObjects(
                'SELECT form, COUNT(*) AS cnt FROM ' . $table . ' GROUP BY form ORDER BY cnt DESC'
            ),
            'byReason' => $this->db->getObjects(
                'SELECT reason, COUNT(*) AS cnt FROM ' . $table . ' GROUP BY reason ORDER BY cnt DESC'
            ),
        ];
    }

    /**
     * Aggregated counters for the auto-normalized (modified) numbers.
     *
     * @return array{total: int, last7: int, byForm: array<stdClass>}
     */
    public function buildModifiedCounts(): array
    {
        $table = ModifiedPhoneLogger::TABLE;

        return [
            'total'  => $this->db->getSingleInt('SELECT COUNT(*) AS cnt FROM ' . $table, 'cnt'),
            'last7'  => $this->db->getSingleInt(
                'SELECT COUNT(*) AS cnt FROM ' . $table
                . ' WHERE created_at >= NOW() - INTERVAL 7 DAY',
                'cnt'
            ),
            'byForm' => $this->db->getObjects(
                'SELECT form, COUNT(*) AS cnt FROM ' . $table . ' GROUP BY form ORDER BY cnt DESC'
            ),
        ];
    }

    public function streamCsv(): never
    {
        $rows = $this->db->getObjects(
            'SELECT id, form, field, raw_value, country_hint, reason, created_at
                FROM ' . InvalidPhoneLogger::TABLE . '
                ORDER BY id DESC'
        );
        $this->streamCsvRows('tnt_ip_invalid_phone', new InvalidPhoneCsv(), $rows);
    }

    public function streamModifiedCsv(): never
    {
        $rows = $this->db->getObjects(
            'SELECT id, form, field, before_value, after_value, country_hint, created_at
                FROM ' . ModifiedPhoneLogger::TABLE . '
                ORDER BY id DESC'
        );
        $this->streamCsvRows('tnt_ip_modified_phone', new InvalidPhoneCsv(InvalidPhoneCsv::MODIFIED_COLUMNS), $rows);
    }

    /**
     * @param array<object> $rows
     */
    private function streamCsvRows(string $filenamePrefix, InvalidPhoneCsv $csv, array $rows): never
    {
        if (\ob_get_length() !== false && \ob_get_length() > 0) {
            \ob_end_clean();
        }
        \header('Content-Type: text/csv; charset=utf-8');
        \header('Content-Disposition: attachment; filename="' . $filenamePrefix . '_' . date('Ymd_His') . '.csv"');
        $out = \fopen('php://output', 'wb');
        if ($out !== false) {
            $csv->write($out, $rows);
            \fclose($out);
        }
        exit;
    }
}
