<?php
namespace Domain\Dashboard;

class DashboardRepository
{
    private $db;

    public function __construct( $db )
    {
        $this->db = $db;
    }

    public function summaryOrders(): int
    {
        try {
            $redis = \Shared\Cache\RedisConnection::getInstance()->getConnection();
            if ( $redis ) {
                $cached = $redis->get( 'summary_ordersd' );
                if ( $cached !== false ) {
                    return (int) unserialize( $cached );
                }
                $summary = (int) $this->db->count( 'pp_shop_orders', [ 'status' => 6 ] );
                $redis->setex( 'summary_ordersd', 300, serialize( $summary ) );
                return $summary;
            }
        } catch ( \RedisException $e ) {
            // fallback
        }

        return (int) $this->db->count( 'pp_shop_orders', [ 'status' => 6 ] );
    }

    public function summarySales(): float
    {
        try {
            $redis = \Shared\Cache\RedisConnection::getInstance()->getConnection();
            if ( $redis ) {
                $cached = $redis->get( 'summary_salesd' );
                if ( $cached !== false ) {
                    return (float) unserialize( $cached );
                }
                $summary = $this->calculateTotalSales();
                $redis->setex( 'summary_salesd', 300, serialize( $summary ) );
                return $summary;
            }
        } catch ( \RedisException $e ) {
            // fallback
        }

        return $this->calculateTotalSales();
    }

    private function calculateTotalSales(): float
    {
        return (float) $this->db->sum( 'pp_shop_orders', 'summary', [ 'status' => 6 ] )
             - (float) $this->db->sum( 'pp_shop_orders', 'transport_cost', [ 'status' => 6 ] );
    }

    public function salesGrid(): array
    {
        $grid = [];
        $rows = $this->db->select( 'pp_shop_orders', [ 'id', 'date_order' ], [ 'status' => 6 ] );

        if ( is_array( $rows ) ) {
            foreach ( $rows as $row ) {
                $ts = strtotime( $row['date_order'] );
                $dayOfWeek = date( 'N', $ts );
                $hour = date( 'G', $ts );
                if ( !isset( $grid[$dayOfWeek][$hour] ) ) {
                    $grid[$dayOfWeek][$hour] = 0;
                }
                $grid[$dayOfWeek][$hour]++;
            }
        }

        return $grid;
    }

    public function mostViewedProducts(): array
    {
        $stmt = $this->db->query(
            'SELECT id, SUM(visits) AS visits '
            . 'FROM pp_shop_products '
            . 'GROUP BY id '
            . 'ORDER BY visits DESC '
            . 'LIMIT 10'
        );

        return $stmt ? $stmt->fetchAll( \PDO::FETCH_ASSOC ) : [];
    }

    public function bestSalesProducts(): array
    {
        $stmt = $this->db->query(
            'SELECT parent_product_id, SUM(quantity) AS quantity_summary, SUM(price_brutto_promo * quantity) AS sales '
            . 'FROM pp_shop_order_products AS psop '
            . 'INNER JOIN pp_shop_orders AS pso ON pso.id = psop.order_id '
            . 'WHERE pso.status = 6 '
            . 'GROUP BY parent_product_id '
            . 'ORDER BY sales DESC '
            . 'LIMIT 10'
        );

        return $stmt ? $stmt->fetchAll( \PDO::FETCH_ASSOC ) : [];
    }

    public function last24MonthsSales(): array
    {
        $sales = [];
        $date = new \DateTime();

        for ( $i = 0; $i < 24; $i++ ) {
            $dateStart = $date->format( 'Y-m-01' );
            $dateEnd = $date->format( 'Y-m-t' );

            $where = [
                'AND' => [
                    'status'          => 6,
                    'date_order[>=]'  => $dateStart,
                    'date_order[<=]'  => $dateEnd,
                ]
            ];

            $monthSales = (float) $this->db->sum( 'pp_shop_orders', 'summary', $where )
                        - (float) $this->db->sum( 'pp_shop_orders', 'transport_cost', $where );

            $sales[] = [
                'date'  => $date->format( 'Y-m' ),
                'sales' => $monthSales,
            ];

            $date->sub( new \DateInterval( 'P1M' ) );
        }

        return $sales;
    }

    public function lastOrders( int $limit = 10 ): array
    {
        $stmt = $this->db->query(
            'SELECT id, number, date_order, '
            . 'CONCAT( client_name, \' \', client_surname ) AS client, '
            . 'client_email, '
            . 'CONCAT( client_street, \', \', client_postal_code, \' \', client_city ) AS address, '
            . 'status, client_phone, summary '
            . 'FROM pp_shop_orders '
            . 'ORDER BY date_order DESC '
            . 'LIMIT ' . (int) $limit
        );

        return $stmt ? $stmt->fetchAll( \PDO::FETCH_ASSOC ) : [];
    }
}
