<?php

namespace App\Controllers;

use App\Services\Database;
use App\Middleware\AuthMiddleware;

/**
 * Controlador de Product Backlog y Sprints
 * Gestiona metodología Scrum: backlog items, sprints, tasks
 */
class BacklogController extends BaseController
{
    protected $db;
    protected $authMiddleware;

    public function __construct()
    {
        parent::__construct();
        $this->db = Database::getInstance();
        $this->authMiddleware = new AuthMiddleware();
    }

    /**
     * Ver backlog de un proyecto específico
     */
    public function index($project_id): void
    {
        $this->authMiddleware->requireRole();

        // Verificar que el proyecto existe
        $project = $this->db->fetchOne("SELECT * FROM projects WHERE id = ?", [$project_id]);
        if (!$project) {
            http_response_code(404);
            echo "Proyecto no encontrado";
            return;
        }

        // Obtener backlog items
        $items = $this->db->fetchAll(
            "SELECT pbi.*, 
                    u1.first_name as creator_first_name, u1.last_name as creator_last_name,
                    u2.first_name as assigned_first_name, u2.last_name as assigned_last_name,
                    r.code as requirement_code, r.title as requirement_title,
                    (SELECT COUNT(*) FROM tasks WHERE backlog_item_id = pbi.id) as tasks_count
             FROM product_backlog_items pbi
             LEFT JOIN users u1 ON pbi.created_by = u1.id
             LEFT JOIN users u2 ON pbi.assigned_to = u2.id
             LEFT JOIN requirements r ON pbi.requirement_id = r.id
             WHERE pbi.project_id = ?
             ORDER BY 
                CASE pbi.priority
                    WHEN 'critical' THEN 1
                    WHEN 'high' THEN 2
                    WHEN 'medium' THEN 3
                    WHEN 'low' THEN 4
                END,
                pbi.created_at DESC",
            [$project_id]
        );

        // Obtener sprints del proyecto
        $sprints = $this->db->fetchAll(
            "SELECT s.*,
                    u.first_name as creator_first_name, u.last_name as creator_last_name,
                    (SELECT COUNT(*) FROM sprint_backlog WHERE sprint_id = s.id) as items_count
             FROM sprints s
             LEFT JOIN users u ON s.created_by = u.id
             WHERE s.project_id = ?
             ORDER BY s.start_date DESC",
            [$project_id]
        );

        // Obtener usuarios para asignación
        $users = $this->db->fetchAll("SELECT id, first_name, last_name, email FROM users WHERE is_active = TRUE");

        // Obtener miembros del equipo del proyecto para asignación de tareas
        $teamMembers = [];
        if (!empty($project['responsible_team_id'])) {
            $teamMembers = $this->db->fetchAll(
                "SELECT u.id, CONCAT(u.first_name, ' ', u.last_name) as name, u.email,
                        tm.is_leader
                 FROM team_members tm
                 INNER JOIN users u ON tm.user_id = u.id
                 WHERE tm.team_id = ? AND u.is_active = TRUE
                 ORDER BY tm.is_leader DESC, u.first_name, u.last_name",
                [$project['responsible_team_id']]
            );
        }

        $csrf_token = $_SESSION['csrf_token'] ?? '';

        require __DIR__ . '/../../views/backlog/index.php';
    }

    /**
     * Crear nuevo backlog item
     */
    public function createItem(): void
    {
        $this->authMiddleware->requireRole();
        header('Content-Type: application/json');

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            echo json_encode(['success' => false, 'message' => 'Método no permitido']);
            return;
        }

        $data = json_decode(file_get_contents('php://input'), true);

        // Validar campos requeridos
        if (empty($data['project_id']) || empty($data['title'])) {
            http_response_code(400);
            echo json_encode(['success' => false, 'message' => 'Faltan campos requeridos']);
            return;
        }

        // Verificar que el proyecto existe
        $project = $this->db->fetchOne("SELECT id FROM projects WHERE id = ?", [$data['project_id']]);
        if (!$project) {
            http_response_code(404);
            echo json_encode(['success' => false, 'message' => 'Proyecto no encontrado']);
            return;
        }

        try {
            $sql = "INSERT INTO product_backlog_items 
                    (project_id, requirement_id, title, description, user_story, acceptance_criteria, 
                     story_points, priority, status, type, created_by, assigned_to)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

            $params = [
                $data['project_id'],
                $data['requirement_id'] ?? null,
                $data['title'],
                $data['description'] ?? null,
                $data['user_story'] ?? null,
                $data['acceptance_criteria'] ?? null,
                $data['story_points'] ?? null,
                $data['priority'] ?? 'medium',
                'backlog', // status por defecto
                $data['type'] ?? 'user_story',
                $_SESSION['user']['id'],
                $data['assigned_to'] ?? null
            ];

            $item_id = $this->db->insert($sql, $params);

            echo json_encode([
                'success' => true,
                'message' => 'Item creado exitosamente',
                'item_id' => $item_id
            ]);
        } catch (\Exception $e) {
            http_response_code(500);
            echo json_encode(['success' => false, 'message' => 'Error al crear item: ' . $e->getMessage()]);
        }
    }

    /**
     * Actualizar backlog item
     */
    public function updateItem($id): void
    {
        $this->authMiddleware->requireRole();
        header('Content-Type: application/json');

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            echo json_encode(['success' => false, 'message' => 'Método no permitido']);
            return;
        }

        $data = json_decode(file_get_contents('php://input'), true);
        $action = $data['action'] ?? 'update_all';

        try {
            switch ($action) {
                case 'update_status':
                    $this->db->query(
                        "UPDATE product_backlog_items SET status = ? WHERE id = ?",
                        [$data['status'], $id]
                    );
                    
                    // Recalcular progreso del proyecto
                    $item = $this->db->fetchOne("SELECT project_id FROM product_backlog_items WHERE id = ?", [$id]);
                    if ($item) {
                        $this->updateProjectProgress($item['project_id']);
                    }
                    
                    echo json_encode(['success' => true, 'message' => 'Estado actualizado']);
                    break;

                case 'assign':
                    $this->db->query(
                        "UPDATE product_backlog_items SET assigned_to = ? WHERE id = ?",
                        [$data['assigned_to'], $id]
                    );
                    echo json_encode(['success' => true, 'message' => 'Item asignado']);
                    break;

                case 'update_all':
                    $sql = "UPDATE product_backlog_items SET 
                            title = ?,
                            description = ?,
                            user_story = ?,
                            acceptance_criteria = ?,
                            story_points = ?,
                            priority = ?,
                            assigned_to = ?
                            WHERE id = ?";
                    
                    $params = [
                        $data['title'],
                        $data['description'] ?? null,
                        $data['user_story'] ?? null,
                        $data['acceptance_criteria'] ?? null,
                        $data['story_points'] ?? null,
                        $data['priority'] ?? 'medium',
                        $data['assigned_to'] ?? null,
                        $id
                    ];

                    $this->db->query($sql, $params);
                    echo json_encode(['success' => true, 'message' => 'Item actualizado']);
                    break;

                default:
                    http_response_code(400);
                    echo json_encode(['success' => false, 'message' => 'Acción no válida']);
            }
        } catch (\Exception $e) {
            http_response_code(500);
            echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
        }
    }

    /**
     * Eliminar backlog item
     */
    public function deleteItem($id): void
    {
        $this->authMiddleware->requireRole();
        header('Content-Type: application/json');

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            echo json_encode(['success' => false, 'message' => 'Método no permitido']);
            return;
        }

        try {
            // Verificar que no esté en ningún sprint activo
            $inSprint = $this->db->fetchOne(
                "SELECT sb.id FROM sprint_backlog sb
                 JOIN sprints s ON sb.sprint_id = s.id
                 WHERE sb.backlog_item_id = ? AND s.status = 'active'",
                [$id]
            );

            if ($inSprint) {
                http_response_code(400);
                echo json_encode([
                    'success' => false, 
                    'message' => 'No se puede eliminar un item que está en un sprint activo'
                ]);
                return;
            }

            $this->db->query("DELETE FROM product_backlog_items WHERE id = ?", [$id]);
            echo json_encode(['success' => true, 'message' => 'Item eliminado']);
        } catch (\Exception $e) {
            http_response_code(500);
            echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
        }
    }

    /**
     * Crear nuevo sprint
     */
    public function createSprint(): void
    {
        $this->authMiddleware->requireRole();
        header('Content-Type: application/json');

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            echo json_encode(['success' => false, 'message' => 'Método no permitido']);
            return;
        }

        $data = json_decode(file_get_contents('php://input'), true);

        // Validar campos requeridos
        if (empty($data['project_id']) || empty($data['name']) || empty($data['start_date']) || empty($data['end_date'])) {
            http_response_code(400);
            echo json_encode(['success' => false, 'message' => 'Faltan campos requeridos']);
            return;
        }

        try {
            $sql = "INSERT INTO sprints (project_id, name, goal, start_date, end_date, created_by)
                    VALUES (?, ?, ?, ?, ?, ?)";

            $params = [
                $data['project_id'],
                $data['name'],
                $data['goal'] ?? null,
                $data['start_date'],
                $data['end_date'],
                $_SESSION['user']['id']
            ];

            $sprint_id = $this->db->insert($sql, $params);

            echo json_encode([
                'success' => true,
                'message' => 'Sprint creado exitosamente',
                'sprint_id' => $sprint_id
            ]);
        } catch (\Exception $e) {
            http_response_code(500);
            echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
        }
    }

    /**
     * Actualizar sprint
     */
    public function updateSprint($id): void
    {
        $this->authMiddleware->requireRole();
        header('Content-Type: application/json');

        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            echo json_encode(['success' => false, 'message' => 'Método no permitido']);
            return;
        }

        $data = json_decode(file_get_contents('php://input'), true);
        $action = $data['action'] ?? 'update_all';

        try {
            switch ($action) {
                case 'update_status':
                    $this->db->query(
                        "UPDATE sprints SET status = ? WHERE id = ?",
                        [$data['status'], $id]
                    );
                    echo json_encode(['success' => true, 'message' => 'Estado del sprint actualizado']);
                    break;

                case 'add_item':
                    // Agregar item al sprint (mantiene su estado actual)
                    $sql = "INSERT INTO sprint_backlog (sprint_id, backlog_item_id, committed_hours)
                            VALUES (?, ?, ?)
                            ON DUPLICATE KEY UPDATE committed_hours = VALUES(committed_hours)";
                    
                    $this->db->query($sql, [
                        $id,
                        $data['backlog_item_id'],
                        $data['committed_hours'] ?? null
                    ]);

                    echo json_encode(['success' => true, 'message' => 'Item agregado al sprint']);
                    break;

                case 'remove_item':
                    $this->db->query(
                        "DELETE FROM sprint_backlog WHERE sprint_id = ? AND backlog_item_id = ?",
                        [$id, $data['backlog_item_id']]
                    );

                    echo json_encode(['success' => true, 'message' => 'Item removido del sprint']);
                    break;

                case 'update_all':
                    $sql = "UPDATE sprints SET 
                            name = ?,
                            goal = ?,
                            start_date = ?,
                            end_date = ?
                            WHERE id = ?";
                    
                    $this->db->query($sql, [
                        $data['name'],
                        $data['goal'] ?? null,
                        $data['start_date'],
                        $data['end_date'],
                        $id
                    ]);
                    echo json_encode(['success' => true, 'message' => 'Sprint actualizado']);
                    break;

                default:
                    http_response_code(400);
                    echo json_encode(['success' => false, 'message' => 'Acción no válida']);
            }
        } catch (\Exception $e) {
            http_response_code(500);
            echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
        }
    }

    /**
     * Ver detalles de un sprint con su backlog
     */
    public function viewSprint($id): void
    {
        $this->authMiddleware->requireRole();

        // Obtener sprint
        $sprint = $this->db->fetchOne(
            "SELECT s.*, p.name as project_name, p.code as project_code,
                    u.first_name as creator_first_name, u.last_name as creator_last_name
             FROM sprints s
             JOIN projects p ON s.project_id = p.id
             LEFT JOIN users u ON s.created_by = u.id
             WHERE s.id = ?",
            [$id]
        );

        if (!$sprint) {
            http_response_code(404);
            echo "Sprint no encontrado";
            return;
        }

        // Obtener items del sprint
        $items = $this->db->fetchAll(
            "SELECT pbi.*, sb.committed_hours, sb.actual_hours,
                    u.first_name as assigned_first_name, u.last_name as assigned_last_name,
                    r.code as requirement_code, r.title as requirement_title,
                    (SELECT COUNT(*) FROM tasks WHERE backlog_item_id = pbi.id) as tasks_count,
                    (SELECT SUM(actual_hours) FROM tasks WHERE backlog_item_id = pbi.id) as tasks_hours
             FROM sprint_backlog sb
             JOIN product_backlog_items pbi ON sb.backlog_item_id = pbi.id
             LEFT JOIN users u ON pbi.assigned_to = u.id
             LEFT JOIN requirements r ON pbi.requirement_id = r.id
             WHERE sb.sprint_id = ?
             ORDER BY pbi.priority DESC, pbi.created_at",
            [$id]
        );

        // Obtener items disponibles para agregar (no asignados a este sprint)
        $available_items = $this->db->fetchAll(
            "SELECT pbi.* 
             FROM product_backlog_items pbi
             WHERE pbi.project_id = ?
             AND pbi.id NOT IN (SELECT backlog_item_id FROM sprint_backlog WHERE sprint_id = ?)
             AND pbi.status NOT IN ('done', 'cancelled')
             ORDER BY 
                CASE pbi.priority
                    WHEN 'critical' THEN 1
                    WHEN 'high' THEN 2
                    WHEN 'medium' THEN 3
                    WHEN 'low' THEN 4
                END",
            [$sprint['project_id'], $id]
        );

        $csrf_token = $_SESSION['csrf_token'] ?? '';

        require __DIR__ . '/../../views/backlog/sprint.php';
    }

    /**
     * Obtener estadísticas del backlog
     */
    public function getStats($project_id): void
    {
        $this->authMiddleware->requireRole();
        header('Content-Type: application/json');

        $stats = [
            'total_items' => $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM product_backlog_items WHERE project_id = ?",
                [$project_id]
            )['count'],
            
            'by_status' => $this->db->fetchAll(
                "SELECT status, COUNT(*) as count FROM product_backlog_items 
                 WHERE project_id = ? GROUP BY status",
                [$project_id]
            ),
            
            'total_story_points' => $this->db->fetchOne(
                "SELECT SUM(story_points) as total FROM product_backlog_items 
                 WHERE project_id = ? AND status NOT IN ('done', 'cancelled')",
                [$project_id]
            )['total'] ?? 0,
            
            'active_sprints' => $this->db->fetchOne(
                "SELECT COUNT(*) as count FROM sprints 
                 WHERE project_id = ? AND status = 'active'",
                [$project_id]
            )['count']
        ];

        echo json_encode($stats);
    }

    /**
     * Actualizar progreso automático del proyecto basado en requerimientos y backlog items
     */
    private function updateProjectProgress($project_id): void
    {
        // Contar requerimientos del proyecto
        $reqStats = $this->db->fetchOne(
            "SELECT 
                COUNT(*) as total,
                SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed
             FROM requirements 
             WHERE project_id = ?",
            [$project_id]
        );

        // Contar backlog items del proyecto
        $backlogStats = $this->db->fetchOne(
            "SELECT 
                COUNT(*) as total,
                SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END) as completed
             FROM product_backlog_items 
             WHERE project_id = ?",
            [$project_id]
        );

        $totalItems = ($reqStats['total'] ?? 0) + ($backlogStats['total'] ?? 0);
        $completedItems = ($reqStats['completed'] ?? 0) + ($backlogStats['completed'] ?? 0);

        if ($totalItems > 0) {
            $progress = round(($completedItems / $totalItems) * 100);
            $this->db->query(
                "UPDATE projects SET progress_percentage = ? WHERE id = ?",
                [$progress, $project_id]
            );
        }
    }

    /**
     * Obtener datos para el burndown chart de un sprint
     */
    public function getBurndownData($sprintId): void
    {
        $this->authMiddleware->requireRole();
        header('Content-Type: application/json');

        try {
            // Obtener sprint
            $sprint = $this->db->fetchOne(
                "SELECT * FROM sprints WHERE id = ?",
                [$sprintId]
            );

            if (!$sprint) {
                http_response_code(404);
                echo json_encode(['success' => false, 'message' => 'Sprint no encontrado']);
                return;
            }

            // Calcular fechas del sprint
            $startDate = new \DateTime($sprint['start_date']);
            $endDate = new \DateTime($sprint['end_date']);
            $currentDate = new \DateTime();
            
            // Si el sprint no ha comenzado aún
            if ($currentDate < $startDate) {
                $currentDate = clone $startDate;
            }
            
            // Si el sprint ya terminó
            if ($currentDate > $endDate) {
                $currentDate = clone $endDate;
            }

            // Obtener story points totales del sprint
            $totalPoints = $this->db->fetchOne(
                "SELECT SUM(pbi.story_points) as total
                 FROM sprint_backlog sb
                 JOIN product_backlog_items pbi ON sb.backlog_item_id = pbi.id
                 WHERE sb.sprint_id = ?",
                [$sprintId]
            )['total'] ?? 0;

            // Generar línea ideal (burndown perfecto)
            $days = $startDate->diff($endDate)->days + 1;
            $idealLine = [];
            $pointsPerDay = $days > 0 ? $totalPoints / $days : 0;

            for ($i = 0; $i < $days; $i++) {
                $date = clone $startDate;
                $date->modify("+{$i} days");
                $idealLine[] = [
                    'date' => $date->format('Y-m-d'),
                    'remaining' => max(0, $totalPoints - ($pointsPerDay * $i))
                ];
            }

            // Obtener datos reales de progreso diario
            $actualLine = [];
            $workLog = $this->db->fetchAll(
                "SELECT DATE(updated_at) as date, 
                        SUM(pbi.story_points) as points_completed
                 FROM product_backlog_items pbi
                 JOIN sprint_backlog sb ON pbi.id = sb.backlog_item_id
                 WHERE sb.sprint_id = ? AND pbi.status = 'done'
                 GROUP BY DATE(updated_at)
                 ORDER BY date ASC",
                [$sprintId]
            );

            // Construir línea real acumulativa
            $completedPoints = 0;
            $currentCheckDate = clone $startDate;
            
            while ($currentCheckDate <= $currentDate) {
                $dateStr = $currentCheckDate->format('Y-m-d');
                
                // Buscar si hay trabajo completado en esta fecha
                foreach ($workLog as $log) {
                    if ($log['date'] === $dateStr) {
                        $completedPoints += (float)$log['points_completed'];
                    }
                }
                
                $actualLine[] = [
                    'date' => $dateStr,
                    'remaining' => max(0, $totalPoints - $completedPoints)
                ];
                
                $currentCheckDate->modify('+1 day');
            }

            // Calcular velocidad y predicción
            $daysElapsed = $startDate->diff($currentDate)->days + 1;
            $velocity = $daysElapsed > 0 ? $completedPoints / $daysElapsed : 0;
            $daysRemaining = $endDate->diff($currentDate)->days;
            $predictedCompletion = $completedPoints + ($velocity * $daysRemaining);

            echo json_encode([
                'success' => true,
                'sprint' => [
                    'id' => $sprint['id'],
                    'name' => $sprint['name'],
                    'start_date' => $sprint['start_date'],
                    'end_date' => $sprint['end_date'],
                    'status' => $sprint['status']
                ],
                'metrics' => [
                    'total_points' => (float)$totalPoints,
                    'completed_points' => $completedPoints,
                    'remaining_points' => max(0, $totalPoints - $completedPoints),
                    'velocity' => round($velocity, 2),
                    'predicted_completion' => round($predictedCompletion, 2),
                    'on_track' => $predictedCompletion >= ($totalPoints * 0.9) // 90% del objetivo
                ],
                'chartData' => [
                    'ideal' => $idealLine,
                    'actual' => $actualLine
                ]
            ]);

        } catch (\Exception $e) {
            error_log("Error getting burndown data: " . $e->getMessage());
            http_response_code(500);
            echo json_encode(['success' => false, 'message' => 'Error al obtener datos del burndown']);
        }
    }
}

