<?php

$action = new action_plugin_bez_base();
$action->createObjects(true);

/**
 * Envia notificaciones de advertencia de vencimiento segun configuracion de semaforizacion
 * Esta funcion debe ejecutarse diariamente via CRON
 */
function send_deadline_warnings() {
    global $action;

    // Obtener configuracion de prioridades activas con notificaciones habilitadas
    $priority_configs = get_active_priority_configs_with_notifications();

    if (empty($priority_configs)) {
        return [];
    }

    // Compilar LESS una sola vez para todas las tareas (cache)
    $style = '';
    try {
        $less = new \LesserPHP\Lessc();
        $less->addImportDir(DOKU_PLUGIN . 'bez/style/');
        $style = $less->compileFile(DOKU_PLUGIN . 'bez/style/task.less');
    } catch (\Exception $e) {
        dbglog('bez cron: error compilando LESS: ' . $e->getMessage());
    }

    $today = date('Y-m-d');
    $output = [];

    foreach ($priority_configs as $config) {
        // Obtener tareas que caen en este rango de dias
        $tasks = get_tasks_in_priority_range($config);

        foreach ($tasks as $task) {
            // Anti-spam: verificar si ya se notifico hoy para esta tarea/nivel
            if (was_deadline_notified_today($task->id, $config['priority_level'], $today)) {
                continue;
            }

            // Calcular dias restantes
            $now = new \DateTime($today);
            $plan = new \DateTime($task->plan_date);
            $diff = $now->diff($plan);
            $days = (int)$diff->format('%r%a');

            try {
                // Enviar notificacion con CSS pre-compilado y asunto personalizado
                $sent_to = $task->mail_notify_deadline_warning($config, $days, $style);

                // Registrar en log anti-spam
                if (!empty($sent_to)) {
                    log_deadline_notification($task->id, $config['priority_level'], $today);
                }

                $output[] = [
                    'task_id' => $task->id,
                    'priority' => $config['priority_level'],
                    'label' => $config['label'],
                    'days' => $days,
                    'sent_to' => $sent_to
                ];
            } catch (\Exception $e) {
                dbglog('bez cron: error notificando tarea #' . $task->id . ': ' . $e->getMessage());
            }
        }
    }

    // Purgar registros antiguos del log (> 90 dias) para evitar crecimiento indefinido
    purge_old_notification_logs();

    return $output;
}

/**
 * Elimina registros del log de notificaciones con mas de 90 dias
 */
function purge_old_notification_logs() {
    global $action;

    try {
        $cutoff = date('Y-m-d', strtotime('-90 days'));
        $sql = "DELETE FROM task_deadline_notification_log WHERE notified_date < ?";
        $action->get_model()->sqlite->query($sql, $cutoff);
    } catch (\Exception $e) {
        // No bloquear el CRON si la purga falla
        dbglog('bez cron: purge_old_notification_logs error: ' . $e->getMessage());
    }
}

/**
 * Verifica si ya se envio notificacion de deadline hoy para una tarea/nivel
 */
function was_deadline_notified_today($task_id, $priority_level, $today) {
    global $action;

    try {
        $sql = "SELECT COUNT(*) as cnt FROM task_deadline_notification_log
                WHERE task_id = ? AND priority_level = ? AND notified_date = ?";
        $result = $action->get_model()->sqlite->query($sql, $task_id, $priority_level, $today);
        if ($result) {
            $row = $action->get_model()->sqlite->res2row($result);
            return $row && (int)$row['cnt'] > 0;
        }
    } catch (\Exception $e) {
        // Si la tabla no existe aun, permitir envio
        dbglog('bez cron: was_deadline_notified_today error: ' . $e->getMessage());
    }

    return false;
}

/**
 * Registra que se envio notificacion de deadline
 */
function log_deadline_notification($task_id, $priority_level, $today) {
    global $action;

    try {
        $sql = "INSERT OR IGNORE INTO task_deadline_notification_log
                (task_id, priority_level, notified_date, recipient)
                VALUES (?, ?, ?, 'all')";
        $action->get_model()->sqlite->query($sql, $task_id, $priority_level, $today);
    } catch (\Exception $e) {
        dbglog('bez cron: log_deadline_notification error: ' . $e->getMessage());
    }
}

/**
 * Obtiene configuraciones de prioridad activas que tienen notificaciones habilitadas
 */
function get_active_priority_configs_with_notifications() {
    global $action;

    try {
        $sql = "SELECT * FROM task_priority_config
                WHERE is_active = 1
                AND (notify_superuser = 1 OR notify_assignee = 1 OR notify_creator = 1)
                ORDER BY sort_order DESC";

        $result = $action->get_model()->sqlite->query($sql);
        if ($result) {
            return $action->get_model()->sqlite->res2arr($result);
        }
    } catch (Exception $e) {
        // Si la tabla no existe, devolver array vacio
        dbglog('bez cron: get_active_priority_configs error: ' . $e->getMessage());
    }

    return [];
}

/**
 * Obtiene tareas abiertas que caen en el rango de dias de una configuracion de prioridad
 */
function get_tasks_in_priority_range($config) {
    global $action;

    $tasks = [];
    $filters = ['state' => 'opened'];

    // Calcular fechas segun el rango de dias
    // Normalizar NULLs: SQLite puede devolver null, '' o 'NULL'
    $from_days = $config['days_from'];
    $to_days = $config['days_to'];
    if ($from_days === 'NULL' || $from_days === '') $from_days = null;
    if ($to_days === 'NULL' || $to_days === '') $to_days = null;

    if ($from_days !== null && $to_days !== null) {
        // Rango especifico
        if ($from_days == $to_days) {
            // Un solo dia
            $target_date = date('Y-m-d', strtotime("+{$from_days} day"));
            $filters['plan_date'] = $target_date;
        } else {
            // Rango de dias: from_days es el minimo de dias, to_days el maximo
            // Ej: Urgente from=1, to=6 → fecha_inicio = hoy+1, fecha_fin = hoy+6
            $date_start = date('Y-m-d', strtotime("+{$from_days} day"));
            $date_end = date('Y-m-d', strtotime("+{$to_days} day"));

            // Asegurar orden correcto para BETWEEN (menor primero)
            if ($date_start > $date_end) {
                $tmp = $date_start;
                $date_start = $date_end;
                $date_end = $tmp;
            }

            $filters['plan_date'] = ['BETWEEN', [$date_start, $date_end]];
        }
    } elseif ($from_days !== null) {
        // Solo limite inferior (>= from_days)
        $target_date = date('Y-m-d', strtotime("+{$from_days} day"));
        $filters['plan_date'] = ['>=', $target_date];
    } elseif ($to_days !== null) {
        // Solo limite superior (<= to_days)
        if ($to_days < 0) {
            // Tareas vencidas
            $target_date = date('Y-m-d', strtotime("{$to_days} day"));
            $filters['plan_date'] = ['<=', $target_date];
        } else {
            $target_date = date('Y-m-d', strtotime("+{$to_days} day"));
            $filters['plan_date'] = ['<=', $target_date];
        }
    }

    try {
        $tasks = $action->get_model()->taskFactory->get_all($filters);
    } catch (Exception $e) {
        // Error obteniendo tareas
        dbglog('bez cron: get_tasks_in_priority_range error: ' . $e->getMessage());
    }

    return $tasks;
}

function send_inactive_issue() {
    global $action;

    $threads = $action->get_model()->threadFactory->get_all(array(
        'last_activity_date' => array('<=', date('c', strtotime('-26 days'))),
        'state' => 'opened'
    ));

    foreach ($threads as $thread) {
        //send reminder once a month
        $day_of_issue_last_activity = date('d', strtotime($thread->last_activity_date));
        if ($day_of_issue_last_activity == date('d')) {
            //send message to all
            $thread->mail_notify_inactive($thread->get_participants('subscribent'));
        }
    }
}

function send_task_reminder() {
    global $action;

    $filters = array('state' => 'opened', 'plan_date' => array('OR', array()));

    $days_before = $action->getConf('task_remaind_days_before');
    $days_before = array_map('trim', explode(',', $days_before));

    if (count($days_before) == 0) {
        return;
    }

    // Obtener configs del semaforo con notificaciones activas para evitar duplicados
    $semaphore_configs = get_active_priority_configs_with_notifications();
    $semaphore_dates = [];
    foreach ($semaphore_configs as $cfg) {
        $from = $cfg['days_from'];
        $to = $cfg['days_to'];
        if ($from === 'NULL' || $from === '') $from = null;
        if ($to === 'NULL' || $to === '') $to = null;
        $semaphore_dates[] = ['from' => $from, 'to' => $to];
    }

    foreach($days_before as $day) {
        $day = (int)$day;

        // Solo omitir este dia si el semaforo ya lo cubre con notificacion
        $covered = false;
        foreach ($semaphore_dates as $range) {
            $matches_from = ($range['from'] === null) || ($day >= (int)$range['from']);
            $matches_to = ($range['to'] === null) || ($day <= (int)$range['to']);
            if ($matches_from && $matches_to) {
                $covered = true;
                break;
            }
        }
        if ($covered) continue;

        $filters['plan_date'][1][] = date('Y-m-d', strtotime("+$day day"));
    }

    // Si todos los dias fueron cubiertos por el semaforo, no hay nada que enviar
    if (empty($filters['plan_date'][1])) {
        return;
    }

    $tasks = $action->get_model()->taskFactory->get_all($filters);

    $now = new \DateTime(date('Y-m-d'));
    foreach ($tasks as $task) {
        $plan_date = new \DateTime($task->plan_date);
        $task->mail_notify_remind($task->get_participants('subscribent'), $plan_date->diff($now)->format('%a'));
    }
}

function send_weekly_message() {
    global $action;
    global $auth;
    global $conf;

    //email => array('user' => array('issues' => array(), 'tasks' => array()))
    $msg = array();
    $output = array();

    $threads = $action->get_model()->threadFactory->get_all(array(
          'type' => 'issue',
          'priority' => array('OR', array('2', '1'))
      ));

    foreach ($threads as $thread) {
        $key = $thread->coordinator;
        if (!isset($msg[$key])) {
            $msg[$key] = array(
                'issues'          => array(),
                'coming_tasks'    => array(),
                'outdated_tasks'  => array()
            );
        }
        $msg[$key]['issues'][] = $thread;
    }

    $tasks  = $action->get_model()->taskFactory->get_all(array(
        'priority' => array('OR', array('2', '1'))
    ));

    foreach ($tasks as $task) {
        $key = $task->assignee;
        if (!isset($msg[$key])) {
            $msg[$key] = array(
                'issues'          => array(),
                'coming_tasks'    => array(),
                'outdated_tasks'  => array()
            );
        }

        if ($task->priority == '1') {
            $msg[$key]['coming_tasks'][] = $task;
        } else {
            $msg[$key]['outdated_tasks'][] = $task;
        }
    }

    //outdated_tasks, coming_tasks, open_tasks
    $muted_users = $action->get_model()->factory('subscription')->getMutedUsers();

    foreach ($msg as $user => $data) {
        $udata = $auth->getUserData($user);
        if (!$udata) continue;

        //omit muted users
        if (in_array($user, $muted_users)) continue;

        $issues = $data['issues'];
        $outdated_tasks = $data['outdated_tasks'];
        $coming_tasks = $data['coming_tasks'];


        if (count($issues) + count($outdated_tasks) + count($coming_tasks) == 0)
            continue;

        $tpl = $action->get_tpl();
        $tpl->set('issues', $issues);
        $tpl->set('outdated_tasks', $outdated_tasks);
        $tpl->set('coming_tasks', $coming_tasks);
        $body = $action->bez_tpl_include('cron/weekly-message', true);

        $mailer = new Mailer();

        $to = $udata['name'].' <'.$udata['mail'].'>';
        $mailer->to($to);
        $clean_title = strtr($conf['title'], [
            'á'=>'a','é'=>'e','í'=>'i','ó'=>'o','ú'=>'u',
            'Á'=>'A','É'=>'E','Í'=>'I','Ó'=>'O','Ú'=>'U',
            'ñ'=>'n','Ñ'=>'N','ü'=>'u','Ü'=>'U'
        ]);
        $subject = $clean_title . ' - Tareas pendientes';
        $mailer->subject($subject);
        $mailer->setBody('', null, null, $body);

        $mailer->send();

        $output[] = array($to, $subject, $body, array());
    }

    return $output;
}
