<?php

namespace Gestoreasy\Core\Fiscal;

use PDO;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Fiscal\Logging\FiscalLogger;

/**
 * Serviço de Notificações Fiscais
 * 
 * Gerencia alertas e notificações relacionadas a documentos fiscais,
 * prazos legais, rejeições e outros eventos fiscais importantes.
 */
class FiscalNotificationService
{
    private PDO $pdo;
    private FiscalLogger $logger;
    private ?bool $legacySchema = null;

    public function __construct()
    {
        $this->pdo = ConnectionManager::forTenant();
        $this->logger = new FiscalLogger();
    }

    private function isLegacySchema(): bool
    {
        if ($this->legacySchema !== null) {
            return $this->legacySchema;
        }
        try {
            $stmt = $this->pdo->query("SHOW COLUMNS FROM fiscal_notifications LIKE 'context_data'");
            $this->legacySchema = $stmt->fetch() ? true : false;
        } catch (\Throwable) {
            $this->legacySchema = false;
        }
        return $this->legacySchema;
    }

    /**
     * Cria uma nova notificação fiscal
     */
    public function createNotification(array $data): int
    {
        $isLegacy = $this->isLegacySchema();

        if ($isLegacy) {
            // Mapear severidade para esquema legado
            $severityMap = [
                'low' => 'info',
                'medium' => 'warning',
                'high' => 'error',
                'critical' => 'critical'
            ];
            $severity = $severityMap[$data['severity'] ?? 'medium'] ?? 'warning';
            $context = [
                'title' => $data['title'] ?? null,
                'document_type' => $data['document_type'] ?? null,
                'document_id' => $data['document_id'] ?? null,
                'rejection_code' => $data['rejection_code'] ?? null,
            ];

            $sql = "INSERT INTO fiscal_notifications 
                    (type, message, severity, status, user_id, context_data, expires_at) 
                    VALUES (?, ?, ?, 'unread', ?, ?, ?)";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([
                $data['type'],
                $data['message'],
                $severity,
                $data['user_id'] ?? null,
                json_encode($context),
                $data['expires_at'] ?? null
            ]);
        } else {
            $sql = "INSERT INTO fiscal_notifications 
                    (type, title, message, severity, document_type, document_id, 
                     rejection_code, user_id, company_id, expires_at) 
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([
                $data['type'],
                $data['title'],
                $data['message'],
                $data['severity'] ?? 'medium',
                $data['document_type'] ?? null,
                $data['document_id'] ?? null,
                $data['rejection_code'] ?? null,
                $data['user_id'] ?? null,
                $data['company_id'] ?? null,
                $data['expires_at'] ?? null
            ]);
        }

        $notificationId = $this->pdo->lastInsertId();
        
        FiscalLogger::log('notifications', 'created', [
            'notification_id' => $notificationId,
            'type' => $data['type'],
            'severity' => $data['severity'] ?? 'medium'
        ]);

        return $notificationId;
    }

    /**
     * Cria notificação de rejeição de documento fiscal
     */
    public function createRejectionNotification(string $documentType, string $documentId, string $rejectionCode, string $rejectionMessage, ?int $userId = null): int
    {
        $titles = [
            'nfce' => 'NFC-e Rejeitada',
            'nfe' => 'NF-e Rejeitada', 
            'cte' => 'CT-e Rejeitado'
        ];

        return $this->createNotification([
            'type' => $documentType . '_rejection',
            'title' => $titles[$documentType] ?? 'Documento Rejeitado',
            'message' => "Documento {$documentId} foi rejeitado: {$rejectionMessage}",
            'severity' => 'high',
            'document_type' => $documentType,
            'document_id' => $documentId,
            'rejection_code' => $rejectionCode,
            'user_id' => $userId
        ]);
    }

    /**
     * Cria notificação de prazo SPED
     */
    public function createSpedDeadlineNotification(string $period, int $daysRemaining, ?int $userId = null): int
    {
        $severity = match(true) {
            $daysRemaining <= 1 => 'critical',
            $daysRemaining <= 3 => 'high',
            $daysRemaining <= 7 => 'medium',
            default => 'low'
        };

        return $this->createNotification([
            'type' => 'sped_deadline',
            'title' => 'Prazo SPED se aproximando',
            'message' => "SPED do período {$period} vence em {$daysRemaining} dia(s)",
            'severity' => $severity,
            'document_type' => 'sped',
            'document_id' => $period,
            'user_id' => $userId,
            'expires_at' => date('Y-m-d H:i:s', strtotime("+{$daysRemaining} days"))
        ]);
    }

    /**
     * Cria notificação de vencimento de certificado
     */
    public function createCertExpiryNotification(string $certName, int $daysRemaining, ?int $userId = null): int
    {
        $severity = match(true) {
            $daysRemaining <= 7 => 'critical',
            $daysRemaining <= 15 => 'high',
            $daysRemaining <= 30 => 'medium',
            default => 'low'
        };

        return $this->createNotification([
            'type' => 'cert_expiry',
            'title' => 'Certificado Digital vencendo',
            'message' => "Certificado {$certName} vence em {$daysRemaining} dia(s)",
            'severity' => $severity,
            'user_id' => $userId,
            'expires_at' => date('Y-m-d H:i:s', strtotime("+{$daysRemaining} days"))
        ]);
    }

    /**
     * Lista notificações do usuário
     */
    public function getUserNotifications(?int $userId = null, string $status = 'all', int $limit = 50): array
    {
        $whereConditions = [];
        $params = [];

        if ($userId) {
            $whereConditions[] = "(user_id = ? OR user_id IS NULL)";
            $params[] = $userId;
        }

        if ($status !== 'all') {
            $whereConditions[] = "status = ?";
            $params[] = $status;
        }

        // Não mostrar notificações expiradas
        $whereConditions[] = "(expires_at IS NULL OR expires_at > NOW())";

        $whereClause = $whereConditions ? 'WHERE ' . implode(' AND ', $whereConditions) : '';

        $safeLimit = max(1, min(100, (int)$limit));
        if ($this->isLegacySchema()) {
            $sql = "SELECT * FROM fiscal_notifications 
                    {$whereClause}
                    ORDER BY 
                        CASE severity 
                            WHEN 'critical' THEN 1 
                            WHEN 'error' THEN 2 
                            WHEN 'warning' THEN 3 
                            WHEN 'info' THEN 4 
                        END,
                        created_at DESC 
                    LIMIT {$safeLimit}";
        } else {
            $sql = "SELECT * FROM fiscal_notifications 
                    {$whereClause}
                    ORDER BY 
                        CASE severity 
                            WHEN 'critical' THEN 1 
                            WHEN 'high' THEN 2 
                            WHEN 'medium' THEN 3 
                            WHEN 'low' THEN 4 
                        END,
                        created_at DESC 
                    LIMIT {$safeLimit}";
        }

        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Marca notificação como lida
     */
    public function markAsRead(int $notificationId): bool
    {
        $sql = "UPDATE fiscal_notifications 
                SET status = 'read', read_at = NOW() 
                WHERE id = ? AND status = 'unread'";

        $stmt = $this->pdo->prepare($sql);
        $result = $stmt->execute([$notificationId]);

        if ($result && $stmt->rowCount() > 0) {
            FiscalLogger::log('notifications', 'read', ['notification_id' => $notificationId]);
        }

        return $result;
    }

    /**
     * Marca notificação como dispensada
     */
    public function dismiss(int $notificationId): bool
    {
        if ($this->isLegacySchema()) {
            $sql = "UPDATE fiscal_notifications 
                    SET status = 'dismissed' 
                    WHERE id = ?";
        } else {
            $sql = "UPDATE fiscal_notifications 
                    SET status = 'dismissed', dismissed_at = NOW() 
                    WHERE id = ?";
        }

        $stmt = $this->pdo->prepare($sql);
        $result = $stmt->execute([$notificationId]);

        if ($result && $stmt->rowCount() > 0) {
            FiscalLogger::log('notifications', 'dismissed', ['notification_id' => $notificationId]);
        }

        return $result;
    }

    /**
     * Conta notificações não lidas do usuário
     */
    public function getUnreadCount(?int $userId = null): int
    {
        $whereConditions = ["status = 'unread'"];
        $params = [];

        if ($userId) {
            $whereConditions[] = "(user_id = ? OR user_id IS NULL)";
            $params[] = $userId;
        }

        // Não contar notificações expiradas
        $whereConditions[] = "(expires_at IS NULL OR expires_at > NOW())";

        $whereClause = 'WHERE ' . implode(' AND ', $whereConditions);

        $sql = "SELECT COUNT(*) FROM fiscal_notifications {$whereClause}";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);

        return (int) $stmt->fetchColumn();
    }

    /**
     * Obtém configurações de notificação do usuário
     */
    public function getUserSettings(int $userId): array
    {
        $sql = "SELECT * FROM fiscal_notification_settings WHERE user_id = ?";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([$userId]);

        $settings = $stmt->fetch(PDO::FETCH_ASSOC);

        // Se não existir, criar configurações padrão
        if (!$settings) {
            $this->createDefaultSettings($userId);
            return $this->getUserSettings($userId);
        }

        return $settings;
    }

    /**
     * Atualiza configurações de notificação do usuário
     */
    public function updateUserSettings(int $userId, array $settings): bool
    {
        $allowedFields = [
            'nfce_rejection_enabled', 'nfe_rejection_enabled', 'cte_rejection_enabled',
            'sped_deadline_enabled', 'cert_expiry_enabled', 'general_alert_enabled',
            'min_severity', 'email_enabled', 'browser_enabled'
        ];

        $updateFields = [];
        $params = [];

        foreach ($settings as $field => $value) {
            if (in_array($field, $allowedFields)) {
                $updateFields[] = "{$field} = ?";
                $params[] = $value;
            }
        }

        if (empty($updateFields)) {
            return false;
        }

        $params[] = $userId;
        $sql = "UPDATE fiscal_notification_settings 
                SET " . implode(', ', $updateFields) . ", updated_at = NOW() 
                WHERE user_id = ?";

        $stmt = $this->pdo->prepare($sql);
        return $stmt->execute($params);
    }

    /**
     * Cria configurações padrão para um usuário
     */
    private function createDefaultSettings(int $userId): void
    {
        $sql = "INSERT INTO fiscal_notification_settings (user_id) VALUES (?)";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([$userId]);
    }

    /**
     * Remove notificações expiradas (limpeza automática)
     */
    public function cleanupExpiredNotifications(): int
    {
        $sql = "DELETE FROM fiscal_notifications 
                WHERE expires_at IS NOT NULL AND expires_at < NOW()";
        
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute();
        
        $deletedCount = $stmt->rowCount();
        
        if ($deletedCount > 0) {
            FiscalLogger::log('notifications', 'cleanup', ['deleted_count' => $deletedCount]);
        }
        
        return $deletedCount;
    }

    /**
     * Verifica e cria alertas automáticos de prazos
     */
    public function checkAndCreateDeadlineAlerts(): array
    {
        $alerts = [];
        
        // Verificar prazos SPED (exemplo: dia 15 do mês seguinte)
        $currentMonth = date('Y-m');
        $nextMonth = date('Y-m', strtotime('+1 month'));
        $spedDeadline = $nextMonth . '-15';
        $daysToDeadline = (strtotime($spedDeadline) - time()) / (60 * 60 * 24);
        
        if ($daysToDeadline <= 7 && $daysToDeadline > 0) {
            // Verificar se já existe notificação para este período
            $sql = "SELECT COUNT(*) FROM fiscal_notifications 
                    WHERE type = 'sped_deadline' 
                    AND document_id = ? 
                    AND status != 'dismissed'";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute([$currentMonth]);
            
            if ($stmt->fetchColumn() == 0) {
                $notificationId = $this->createSpedDeadlineNotification($currentMonth, (int)$daysToDeadline);
                $alerts[] = ['type' => 'sped_deadline', 'notification_id' => $notificationId];
            }
        }
        
        return $alerts;
    }
}