<?php

declare(strict_types=1);

namespace CloudXM\NFe\Persistence;

use CloudXM\SDK\Support\HasLogger;

/**
 * NFe History Repository
 *
 * Manages NFe history records in database
 */
class NfeHistoryRepository
{
    use HasLogger;

    private string $table_prefix;

    /**
     * Constructor
     */
    public function __construct(string $table_prefix = 'nfe_')
    {
        $this->table_prefix = $table_prefix;
    }

    /**
     * Get table name
     */
    private function getTableName(): string
    {
        global $wpdb;
        return $wpdb->prefix . $this->table_prefix . 'history';
    }

    /**
     * Add history event
     *
     * @param array $data History event data
     * @return int|false History ID or false on failure
     */
    public function add(array $data)
    {
        global $wpdb;

        $result = $wpdb->insert(
            $this->getTableName(),
            $data,
            $this->getFormats($data)
        );

        if ($result === false) {
            $this->log()->error('nfe.history.add_failed', [
                'data' => $data,
                'error' => $wpdb->last_error,
            ]);
            return false;
        }

        $history_id = $wpdb->insert_id;
        
        $this->log()->debug('nfe.history.event_added', [
            'history_id' => $history_id,
            'emission_id' => $data['emission_id'] ?? null,
            'event_type' => $data['event_type'] ?? null,
        ]);

        return $history_id;
    }

    /**
     * Get history by emission ID
     *
     * @param int $emissionId Emission ID
     * @param int $limit Maximum number of records
     * @param int $offset Offset for pagination
     * @return array List of history events
     */
    public function findByEmissionId(int $emissionId, int $limit = 50, int $offset = 0): array
    {
        global $wpdb;

        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$this->getTableName()} 
                 WHERE emission_id = %d 
                 ORDER BY created_at DESC 
                 LIMIT %d OFFSET %d",
                $emissionId,
                $limit,
                $offset
            ),
            ARRAY_A
        );

        return $results ?: [];
    }

    /**
     * Get history by event type
     *
     * @param int $emissionId Emission ID
     * @param string $eventType Event type
     * @param int $limit Maximum number of records
     * @return array List of history events
     */
    public function findByEventType(int $emissionId, string $eventType, int $limit = 50): array
    {
        global $wpdb;

        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$this->getTableName()} 
                 WHERE emission_id = %d 
                 AND event_type = %s 
                 ORDER BY created_at DESC 
                 LIMIT %d",
                $emissionId,
                $eventType,
                $limit
            ),
            ARRAY_A
        );

        return $results ?: [];
    }

    /**
     * Get history by event status
     *
     * @param int $emissionId Emission ID
     * @param string $eventStatus Event status
     * @param int $limit Maximum number of records
     * @return array List of history events
     */
    public function findByEventStatus(int $emissionId, string $eventStatus, int $limit = 50): array
    {
        global $wpdb;

        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$this->getTableName()} 
                 WHERE emission_id = %d 
                 AND event_status = %s 
                 ORDER BY created_at DESC 
                 LIMIT %d",
                $emissionId,
                $eventStatus,
                $limit
            ),
            ARRAY_A
        );

        return $results ?: [];
    }

    /**
     * Get history by date range
     *
     * @param \DateTime $startDate Start date
     * @param \DateTime $endDate End date
     * @param int $limit Maximum number of records
     * @param int $offset Offset for pagination
     * @return array List of history events
     */
    public function findByDateRange(\DateTime $startDate, \DateTime $endDate, int $limit = 50, int $offset = 0): array
    {
        global $wpdb;

        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$this->getTableName()} 
                 WHERE created_at BETWEEN %s AND %s 
                 ORDER BY created_at DESC 
                 LIMIT %d OFFSET %d",
                $startDate->format('Y-m-d H:i:s'),
                $endDate->format('Y-m-d H:i:s'),
                $limit,
                $offset
            ),
            ARRAY_A
        );

        return $results ?: [];
    }

    /**
     * Get history by user ID
     *
     * @param int $userId User ID
     * @param int $limit Maximum number of records
     * @param int $offset Offset for pagination
     * @return array List of history events
     */
    public function findByUserId(int $userId, int $limit = 50, int $offset = 0): array
    {
        global $wpdb;

        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$this->getTableName()} 
                 WHERE user_id = %d 
                 ORDER BY created_at DESC 
                 LIMIT %d OFFSET %d",
                $userId,
                $limit,
                $offset
            ),
            ARRAY_A
        );

        return $results ?: [];
    }

    /**
     * Get recent history events
     *
     * @param int $limit Maximum number of records
     * @param int $offset Offset for pagination
     * @return array List of recent history events
     */
    public function getRecent(int $limit = 50, int $offset = 0): array
    {
        global $wpdb;

        $results = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$this->getTableName()} 
                 ORDER BY created_at DESC 
                 LIMIT %d OFFSET %d",
                $limit,
                $offset
            ),
            ARRAY_A
        );

        return $results ?: [];
    }

    /**
     * Count history events by emission ID
     *
     * @param int $emissionId Emission ID
     * @return int Number of history events
     */
    public function countByEmissionId(int $emissionId): int
    {
        global $wpdb;

        return (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->getTableName()} WHERE emission_id = %d",
                $emissionId
            )
        );
    }

    /**
     * Count history events by type
     *
     * @param int $emissionId Emission ID
     * @param string $eventType Event type
     * @return int Number of history events
     */
    public function countByEventType(int $emissionId, string $eventType): int
    {
        global $wpdb;

        return (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->getTableName()} 
                 WHERE emission_id = %d 
                 AND event_type = %s",
                $emissionId,
                $eventType
            )
        );
    }

    /**
     * Get history statistics by emission
     *
     * @param int $emissionId Emission ID
     * @return array Statistics data
     */
    public function getStatisticsByEmission(int $emissionId): array
    {
        global $wpdb;

        $stats = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT 
                    COUNT(*) as total_events,
                    COUNT(CASE WHEN event_type = 'emission' THEN 1 END) as emission_events,
                    COUNT(CASE WHEN event_type = 'cancellation' THEN 1 END) as cancellation_events,
                    COUNT(CASE WHEN event_type = 'status_change' THEN 1 END) as status_change_events,
                    COUNT(CASE WHEN event_type = 'retry' THEN 1 END) as retry_events,
                    COUNT(CASE WHEN event_status = 'success' THEN 1 END) as success_events,
                    COUNT(CASE WHEN event_status = 'error' THEN 1 END) as error_events
                FROM {$this->getTableName()}
                WHERE emission_id = %d",
                $emissionId
            ),
            ARRAY_A
        );

        return $stats ?: [];
    }

    /**
     * Delete history events by emission ID
     *
     * @param int $emissionId Emission ID
     * @return int Number of deleted records
     */
    public function deleteByEmissionId(int $emissionId): int
    {
        global $wpdb;

        $result = $wpdb->delete(
            $this->getTableName(),
            ['emission_id' => $emissionId],
            ['%d']
        );

        if ($result === false) {
            $this->log()->error('nfe.history.delete_by_emission_failed', [
                'emission_id' => $emissionId,
                'error' => $wpdb->last_error,
            ]);
            return 0;
        }

        $this->log()->info('nfe.history.deleted_by_emission', [
            'emission_id' => $emissionId,
            'count' => $result,
        ]);

        return $result;
    }

    /**
     * Delete history events older than specified days
     *
     * @param int $daysOld Delete events older than this many days
     * @return int Number of deleted records
     */
    public function deleteOldEvents(int $daysOld = 90): int
    {
        global $wpdb;

        $result = $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$this->getTableName()} 
                 WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
                $daysOld
            )
        );

        if ($result === false) {
            $this->log()->error('nfe.history.delete_old_failed', [
                'days_old' => $daysOld,
                'error' => $wpdb->last_error,
            ]);
            return 0;
        }

        $this->log()->info('nfe.history.old_events_deleted', [
            'days_old' => $daysOld,
            'count' => $result,
        ]);

        return $result;
    }

    /**
     * Get format placeholders for data
     *
     * @param array $data Data array
     * @return array Format placeholders
     */
    private function getFormats(array $data): array
    {
        $formats = [];
        
        foreach ($data as $key => $value) {
            if (is_int($value)) {
                $formats[] = '%d';
            } elseif (is_float($value)) {
                $formats[] = '%f';
            } else {
                $formats[] = '%s';
            }
        }
        
        return $formats;
    }
}
