<?php
declare(strict_types=1);

namespace Celena\Plugin\Shop\Admin;

use Celena\Core\Database\Connection;
use Celena\Core\Http\Request;
use Celena\Core\Http\Response;
use Celena\Core\Security\Auth;
use Celena\Core\Security\Filter;
use Celena\Core\Template\Engine;
use Celena\Module\AdminBase\AdminController;
use Celena\Module\Settings\Options;
use Celena\Plugin\Shop\Support\ShopSettings;

/**
 * Аналитика магазина. Без сторонних библиотек графиков — выводим
 * KPI-карточки и бар-чарт по дням простыми CSS-блоками.
 *
 * Поддерживается переключатель периода: 7 / 30 / 90 дней (?range=7|30|90).
 * Из расчётов выручки исключаются отменённые заказы.
 */
final class AnalyticsAdminController extends AdminController
{
    private function tr(): \Celena\Core\I18n\Translator
    {
        return \Celena\Core\Kernel::container()->make(\Celena\Core\I18n\Translator::class);
    }

    public function __construct(
        Engine $engine,
        Auth $auth,
        Options $options,
        private readonly Connection $conn,
    ) {
        parent::__construct($engine, $auth, $options);
    }

    public function index(Request $request): Response
    {
        if (!$this->auth->check()) return Response::redirect('/admin/login');

        $range = Filter::int($request->query('range', 30), 30);
        if (!in_array($range, [7, 30, 90], true)) $range = 30;

        $today  = date('Y-m-d');
        $from   = date('Y-m-d', strtotime('-' . ($range - 1) . ' days'));
        $cancelled = 'cancelled';

        $shop = new ShopSettings($this->options);
        $fmt = fn (float $v): string => $shop->formatPrice($v);

        // KPI: выручка / заказы / средний чек / клиенты — за выбранный период.
        $orders = 0; $revenue = 0.0; $clients = 0; $aov = 0.0;
        try {
            $row = $this->conn->run(
                'SELECT COUNT(*) AS c, COALESCE(SUM(' . $this->conn->quoteId('total') . '),0) AS s, '
                . 'COUNT(DISTINCT ' . $this->conn->quoteId('customer_email') . ') AS u '
                . 'FROM ' . $this->conn->table_q('shop_orders') . ' '
                . 'WHERE ' . $this->conn->quoteId('created_at') . ' >= ? '
                . 'AND ' . $this->conn->quoteId('status') . ' <> ?',
                [$from . ' 00:00:00', $cancelled]
            )->fetch();
            $orders  = (int) ($row['c'] ?? 0);
            $revenue = (float) ($row['s'] ?? 0);
            $clients = (int) ($row['u'] ?? 0);
            $aov     = $orders > 0 ? $revenue / $orders : 0.0;
        } catch (\Throwable) {}

        // Сегодня — отдельная мини-метрика для подзаголовка KPI «выручка».
        $revenueToday = 0.0; $ordersToday = 0;
        try {
            $row = $this->conn->run(
                'SELECT COUNT(*) AS c, COALESCE(SUM(' . $this->conn->quoteId('total') . '),0) AS s '
                . 'FROM ' . $this->conn->table_q('shop_orders') . ' '
                . 'WHERE ' . $this->conn->quoteId('created_at') . ' >= ? '
                . 'AND ' . $this->conn->quoteId('status') . ' <> ?',
                [$today . ' 00:00:00', $cancelled]
            )->fetch();
            $ordersToday  = (int) ($row['c'] ?? 0);
            $revenueToday = (float) ($row['s'] ?? 0);
        } catch (\Throwable) {}

        // Сводные метрики каталога (не зависят от периода).
        $totalProducts = (int) $this->conn->builder('shop_products')->count();
        $outOfStock    = (int) $this->conn->builder('shop_products')->where('stock', '=', 0)->count();
        $totalReviews  = 0;
        try { $totalReviews = (int) $this->conn->builder('shop_reviews')->count(); } catch (\Throwable) {}
        $newOrders = (int) $this->conn->builder('shop_orders')->where('status', '=', 'new')->count();

        // Бар-чарт по дням периода.
        $byDay = [];
        $maxRev = 0.01;
        try {
            $rows = $this->conn->run(
                'SELECT DATE(' . $this->conn->quoteId('created_at') . ') AS d, '
                . 'COUNT(*) AS c, COALESCE(SUM(' . $this->conn->quoteId('total') . '),0) AS s '
                . 'FROM ' . $this->conn->table_q('shop_orders') . ' '
                . 'WHERE ' . $this->conn->quoteId('created_at') . ' >= ? '
                . 'AND ' . $this->conn->quoteId('status') . ' <> ? '
                . 'GROUP BY DATE(' . $this->conn->quoteId('created_at') . ')',
                [$from . ' 00:00:00', $cancelled]
            )->fetchAll();
            $idx = [];
            foreach ($rows as $r) $idx[(string) $r['d']] = $r;
            for ($i = $range - 1; $i >= 0; $i--) {
                $d = date('Y-m-d', strtotime("-$i days"));
                $rev = isset($idx[$d]) ? (float) $idx[$d]['s'] : 0.0;
                $cnt = isset($idx[$d]) ? (int) $idx[$d]['c'] : 0;
                if ($rev > $maxRev) $maxRev = $rev;
                $byDay[] = [
                    'day'   => $d,
                    'short' => date('d.m', strtotime($d)),
                    'count' => $cnt,
                    'rev'   => $rev,
                    'rev_fmt' => $fmt($rev),
                ];
            }
            foreach ($byDay as &$d) {
                $d['pct'] = (int) round(($d['rev'] / $maxRev) * 100);
            }
            unset($d);
        } catch (\Throwable) {}

        // Топ-5 товаров по выручке за период.
        $topProducts = [];
        try {
            $sql = 'SELECT oi.' . $this->conn->quoteId('product_id') . ' AS pid, '
                . 'oi.' . $this->conn->quoteId('product_title') . ' AS title, '
                . 'SUM(oi.' . $this->conn->quoteId('quantity') . ') AS qty, '
                . 'SUM(oi.' . $this->conn->quoteId('quantity') . ' * oi.' . $this->conn->quoteId('price') . ') AS revenue '
                . 'FROM ' . $this->conn->table_q('shop_order_items') . ' oi '
                . 'INNER JOIN ' . $this->conn->table_q('shop_orders') . ' o ON o.' . $this->conn->quoteId('id') . ' = oi.' . $this->conn->quoteId('order_id') . ' '
                . 'WHERE o.' . $this->conn->quoteId('created_at') . ' >= ? '
                . 'AND o.' . $this->conn->quoteId('status') . ' <> ? '
                . 'GROUP BY oi.' . $this->conn->quoteId('product_id') . ', oi.' . $this->conn->quoteId('product_title') . ' '
                . 'ORDER BY revenue DESC LIMIT 5';
            $topProducts = $this->conn->run($sql, [$from . ' 00:00:00', $cancelled])->fetchAll();
            $i = 1;
            foreach ($topProducts as &$p) {
                $p['revenue_fmt'] = $fmt((float) $p['revenue']);
                $p['position'] = $i++;
            }
            unset($p);
        } catch (\Throwable) {}

        // Распределение по статусам — мини-плашки.
        $statusBreakdown = [];
        try {
            $rows = $this->conn->run(
                'SELECT ' . $this->conn->quoteId('status') . ' AS s, COUNT(*) AS c '
                . 'FROM ' . $this->conn->table_q('shop_orders') . ' '
                . 'WHERE ' . $this->conn->quoteId('created_at') . ' >= ? '
                . 'GROUP BY ' . $this->conn->quoteId('status'),
                [$from . ' 00:00:00']
            )->fetchAll();
            foreach ($rows as $r) {
                $statusBreakdown[] = ['status' => (string) $r['s'], 'count' => (int) $r['c']];
            }
        } catch (\Throwable) {}

        return $this->view('plugins/shop/admin/analytics_index', [
            'range'   => $range,
            'kpi' => [
                ['label' => 'Выручка',     'value' => $fmt($revenue),
                 'sub'   => 'сегодня — ' . $fmt($revenueToday), 'tone' => 'rev'],
                ['label' => 'Заказы',      'value' => (string) $orders,
                 'sub'   => 'сегодня — ' . $ordersToday, 'tone' => 'ord'],
                ['label' => 'Средний чек', 'value' => $orders > 0 ? $fmt($aov) : '—',
                 'sub'   => 'по периоду', 'tone' => 'aov'],
                ['label' => 'Клиенты',     'value' => (string) $clients,
                 'sub'   => 'уникальных за период', 'tone' => 'cli'],
            ],
            'catalog_kpi' => [
                ['label' => 'Товаров в каталоге', 'value' => (string) $totalProducts],
                ['label' => 'Не в наличии',       'value' => (string) $outOfStock],
                ['label' => 'Заказов «новых»',    'value' => (string) $newOrders],
                ['label' => 'Отзывов всего',      'value' => (string) $totalReviews],
            ],
            'by_day'        => $byDay,
            'top_products'  => $topProducts,
            'status_breakdown' => $statusBreakdown,
            'has_data'      => $orders > 0,
        ], 'shop-analytics', $this->tr()->translate('shop.analytics.title'));
    }
}
