<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\Notification;
use App\Models\Database;

class NotificationService
{
    private Notification $notificationModel;
    private MailService $mailService;

    private const TYPE_LABEL = [
        'llamada' => 'Llamar cliente',
        'reunion' => 'Visita técnica',
        'correo' => 'Enviar cotización',
        'whatsapp' => 'WhatsApp',
        'seguimiento' => 'Seguimiento',
        'otro' => 'Otro',
    ];

    public function __construct()
    {
        $this->notificationModel = new Notification();
        $this->mailService = new MailService();
    }

    public function createNotification(int $userId, string $type, string $title, ?string $message, ?string $refType = null, ?int $refId = null): array
    {
        $id = $this->notificationModel->createNotification([
            'user_id' => $userId,
            'type' => $type,
            'title' => $title,
            'message' => $message,
            'reference_type' => $refType,
            'reference_id' => $refId,
        ]);

        return $this->notificationModel->findById($id);
    }

    public function getUserNotifications(int $userId, int $page = 1, int $perPage = 20): array
    {
        return $this->notificationModel->getUserNotifications($userId, $page, $perPage);
    }

    public function markAsRead(int $id): void
    {
        $notification = $this->notificationModel->findById($id);
        if (!$notification) {
            throw new \RuntimeException('Notificación no encontrada', 404);
        }
        $this->notificationModel->markAsRead($id);
    }

    public function markAllAsRead(int $userId): void
    {
        $this->notificationModel->markAllAsRead($userId);
    }

    public function checkUpcomingTasks(): int
    {
        $db = Database::connect();
        $now = date('Y-m-d H:i:s');
        $later = date('Y-m-d H:i:s', strtotime('+1 hour'));
        $stmt = $db->prepare(
            "SELECT t.*, l.first_name, l.last_name, u.email as user_email, u.name as user_name
             FROM tasks t
             LEFT JOIN leads l ON t.lead_id = l.id
             LEFT JOIN users u ON t.assigned_to = u.id
             WHERE t.status = 'pendiente'
             AND CONCAT(t.scheduled_date, ' ', IFNULL(t.scheduled_time, '00:00')) BETWEEN :now AND :later
             AND NOT EXISTS (
               SELECT 1 FROM notifications n
               WHERE n.reference_type = 'task'
               AND n.reference_id = t.id
               AND n.type = 'tarea_proxima'
             )
             LIMIT 100"
        );
        $stmt->execute(['now' => $now, 'later' => $later]);
        $tasks = $stmt->fetchAll();

        $count = 0;
        $batch = [];
        foreach ($tasks as $task) {
            $typeLabel = self::TYPE_LABEL[$task['type']] ?? $task['type'];
            $leadName = $task['first_name'] . ' ' . $task['last_name'];

            $batch[] = [
                'user_id' => (int) $task['assigned_to'],
                'type' => 'tarea_proxima',
                'title' => "Tarea próxima: {$typeLabel}",
                'message' => "Tarea '{$typeLabel}' para {$leadName} a las {$task['scheduled_time']}",
                'reference_type' => 'task',
                'reference_id' => (int) $task['id'],
            ];

            if (!empty($task['user_email']) && $this->mailService->isConfigured()) {
                $this->mailService->sendTaskReminder(
                    $task['user_email'],
                    $typeLabel,
                    $leadName,
                    $task['scheduled_date'],
                    $task['scheduled_time'] ?? ''
                );
            }
            $this->sendToAdmins($typeLabel, $leadName, $task['scheduled_date'], $task['scheduled_time'] ?? '');

            $count++;
        }
        if (!empty($batch)) {
            $this->batchInsertNotifications($batch);
        }

        return $count;
    }

    public function checkTodayTasks(): int
    {
        $db = Database::connect();
        $today = date('Y-m-d');
        $stmt = $db->prepare(
             "SELECT t.*, l.first_name, l.last_name, u.email as user_email, u.name as user_name
              FROM tasks t
              LEFT JOIN leads l ON t.lead_id = l.id
              LEFT JOIN users u ON t.assigned_to = u.id
              WHERE t.status = 'pendiente'
              AND t.scheduled_date = :today
             AND NOT EXISTS (
               SELECT 1 FROM notifications n
               WHERE n.reference_type = 'task'
               AND n.reference_id = t.id
               AND n.type = 'tarea_hoy'
             )
             LIMIT 100"
        );
        $stmt->execute(['today' => $today]);
        $tasks = $stmt->fetchAll();

        $count = 0;
        $batch = [];
        foreach ($tasks as $task) {
            $typeLabel = self::TYPE_LABEL[$task['type']] ?? $task['type'];
            $leadName = $task['first_name'] . ' ' . $task['last_name'];

            $batch[] = [
                'user_id' => (int) $task['assigned_to'],
                'type' => 'tarea_hoy',
                'title' => "Tarea para hoy: {$typeLabel}",
                'message' => "Tienes una tarea '{$typeLabel}' para {$leadName} programada para hoy ({$task['scheduled_date']})" . (!empty($task['scheduled_time']) ? " a las {$task['scheduled_time']}" : ''),
                'reference_type' => 'task',
                'reference_id' => (int) $task['id'],
            ];

            if (!empty($task['user_email']) && $this->mailService->isConfigured()) {
                $this->mailService->sendTaskReminder(
                    $task['user_email'],
                    $typeLabel,
                    $leadName,
                    $task['scheduled_date'],
                    $task['scheduled_time'] ?? ''
                );
            }
            $this->sendToAdmins($typeLabel, $leadName, $task['scheduled_date'], $task['scheduled_time'] ?? '');

            $count++;
        }
        if (!empty($batch)) {
            $this->batchInsertNotifications($batch);
        }

        return $count;
    }

    public function checkOverdueTasks(): int
    {
        $db = Database::connect();
        $now = date('Y-m-d H:i:s');
        $stmt = $db->prepare(
             "SELECT t.*, l.first_name, l.last_name, u.email as user_email, u.name as user_name
              FROM tasks t
              LEFT JOIN leads l ON t.lead_id = l.id
              LEFT JOIN users u ON t.assigned_to = u.id
              WHERE t.status = 'pendiente'
              AND CONCAT(t.scheduled_date, ' ', IFNULL(t.scheduled_time, '23:59')) < :now
             AND NOT EXISTS (
               SELECT 1 FROM notifications n
               WHERE n.reference_type = 'task'
               AND n.reference_id = t.id
               AND n.type = 'tarea_vencida'
             )
             LIMIT 100"
        );
        $stmt->execute(['now' => $now]);
        $tasks = $stmt->fetchAll();

        $count = 0;
        $batch = [];
        foreach ($tasks as $task) {
            $typeLabel = self::TYPE_LABEL[$task['type']] ?? $task['type'];
            $leadName = $task['first_name'] . ' ' . $task['last_name'];

            $batch[] = [
                'user_id' => (int) $task['assigned_to'],
                'type' => 'tarea_vencida',
                'title' => "Tarea vencida: {$typeLabel}",
                'message' => "La tarea '{$typeLabel}' para {$leadName} del {$task['scheduled_date']} está vencida",
                'reference_type' => 'task',
                'reference_id' => (int) $task['id'],
            ];

            if (!empty($task['user_email']) && $this->mailService->isConfigured()) {
                $this->mailService->sendTaskReminder(
                    $task['user_email'],
                    $typeLabel,
                    $leadName,
                    $task['scheduled_date'],
                    $task['scheduled_time'] ?? ''
                );
            }
            $this->sendToAdmins($typeLabel, $leadName, $task['scheduled_date'], $task['scheduled_time'] ?? '');

            $count++;
        }
        if (!empty($batch)) {
            $this->batchInsertNotifications($batch);
        }

        return $count;
    }

    private function sendToAdmins(string $typeLabel, string $leadName, string $scheduledDate, string $scheduledTime): void
    {
        try {
            $db = Database::connect();
            $admins = $db->query("SELECT email FROM users WHERE role = 'super_admin' AND status = 'active' LIMIT 20")->fetchAll();
            foreach ($admins as $admin) {
                if (!empty($admin['email']) && $this->mailService->isConfigured()) {
                    $this->mailService->sendTaskReminder(
                        $admin['email'],
                        $typeLabel,
                        $leadName,
                        $scheduledDate,
                        $scheduledTime
                    );
                }
            }
        } catch (\Throwable $e) {
            error_log('Error notificando a admins: ' . $e->getMessage());
        }
    }

    private function batchInsertNotifications(array $batch): void
    {
        $db = Database::connect();
        $columns = ['user_id', 'type', 'title', 'message', 'reference_type', 'reference_id'];
        $placeholders = [];
        $values = [];
        $i = 0;
        foreach ($batch as $row) {
            $rowPlaceholders = [];
            foreach ($columns as $col) {
                $key = ":$col$i";
                $rowPlaceholders[] = $key;
                $values[$key] = $row[$col] ?? null;
            }
            $placeholders[] = '(' . implode(',', $rowPlaceholders) . ')';
            $i++;
        }
        $sql = "INSERT INTO notifications (" . implode(',', $columns) . ") VALUES " . implode(',', $placeholders);
        $stmt = $db->prepare($sql);
        $stmt->execute($values);
    }
}
