<?php
declare(strict_types=1);

namespace Infolab\Controllers;

use Infolab\ActivityLogger;
use Infolab\Database;
use Infolab\Request;
use Infolab\Response;
use Infolab\Validator;

/**
 * Étapes de feuille de route d'un projet.
 */
final class RoadmapController
{
    public function index(Request $req, array $params): void
    {
        $p = ProjectsController::findOr404($params['slug']);
        $rows = Database::fetchAll(
            'SELECT id, project_id, title, description, step_date, is_done, sort_order, created_at, updated_at
             FROM roadmap_steps WHERE project_id = :pid ORDER BY sort_order ASC, id ASC',
            [':pid' => (int) $p['id']],
        );
        Response::json(['data' => array_map([self::class, 'present'], $rows)]);
    }

    public function store(Request $req, array $params): void
    {
        $p = ProjectsController::findOr404($params['slug']);
        $body = $req->json();
        $v = new Validator($body);
        $v->required('title')->string('title', 200);
        $v->string('description', 5000);
        $v->date('step_date');
        $v->boolean('is_done');
        $v->integer('sort_order', 0);
        $v->check();

        $sortOrder = isset($body['sort_order'])
            ? (int) $body['sort_order']
            : self::nextSortOrder((int) $p['id']);

        $id = Database::insert('roadmap_steps', [
            'project_id'  => (int) $p['id'],
            'title'       => (string) $body['title'],
            'description' => $body['description'] ?? null,
            'step_date'   => $body['step_date'] ?? null,
            'is_done'     => self::toBool($body['is_done'] ?? false) ? 1 : 0,
            'sort_order'  => $sortOrder,
        ]);

        ActivityLogger::log(
            'added_step',
            sprintf('a ajouté l\'étape « %s » au projet « %s »', (string) $body['title'], $p['title']),
            (int) $p['id'],
        );

        Response::json(self::present(self::findStepOr404($id, (int) $p['id'])), 201);
    }

    public function update(Request $req, array $params): void
    {
        $p    = ProjectsController::findOr404($params['slug']);
        $step = self::findStepOr404((int) $params['id'], (int) $p['id']);

        $body = $req->json();
        $v = new Validator($body);
        $v->string('title', 200);
        $v->string('description', 5000);
        $v->date('step_date');
        $v->boolean('is_done');
        $v->integer('sort_order', 0);
        $v->check();

        $update = [];
        foreach (['title', 'description', 'step_date', 'sort_order'] as $f) {
            if (array_key_exists($f, $body)) {
                $update[$f] = $body[$f];
            }
        }
        if (isset($update['sort_order'])) {
            $update['sort_order'] = (int) $update['sort_order'];
        }

        $becameDone = false;
        if (array_key_exists('is_done', $body)) {
            $newDone = self::toBool($body['is_done']);
            $oldDone = (bool) $step['is_done'];
            $update['is_done'] = $newDone ? 1 : 0;
            if ($newDone && !$oldDone) {
                $becameDone = true;
            }
        }
        if ($update !== []) {
            Database::update('roadmap_steps', $update, 'id = :id', [':id' => (int) $step['id']]);
        }
        if ($becameDone) {
            ActivityLogger::log(
                'completed_step',
                sprintf('a terminé l\'étape « %s » du projet « %s »', $step['title'], $p['title']),
                (int) $p['id'],
            );
        }

        Response::json(self::present(self::findStepOr404((int) $step['id'], (int) $p['id'])));
    }

    public function destroy(Request $req, array $params): void
    {
        $p    = ProjectsController::findOr404($params['slug']);
        $step = self::findStepOr404((int) $params['id'], (int) $p['id']);
        Database::delete('roadmap_steps', 'id = :id', [':id' => (int) $step['id']]);
        Response::noContent();
    }

    private static function findStepOr404(int $id, int $projectId): array
    {
        $row = Database::fetchOne(
            'SELECT id, project_id, title, description, step_date, is_done, sort_order, created_at, updated_at
             FROM roadmap_steps WHERE id = :id AND project_id = :pid',
            [':id' => $id, ':pid' => $projectId],
        );
        if ($row === null) {
            throw new \ApiException(404, ['error' => 'not_found']);
        }
        return $row;
    }

    /** Sort order par défaut : MAX + 10 par projet (laisse de l'espace pour insertion ultérieure). */
    private static function nextSortOrder(int $projectId): int
    {
        return (int) Database::fetchValue(
            'SELECT COALESCE(MAX(sort_order), 0) + 10 FROM roadmap_steps WHERE project_id = :pid',
            [':pid' => $projectId],
        );
    }

    private static function toBool(mixed $v): bool
    {
        if (is_bool($v)) return $v;
        if (is_int($v))  return $v !== 0;
        if (is_string($v)) return in_array(strtolower($v), ['true', '1', 'yes', 'on'], true);
        return (bool) $v;
    }

    private static function present(array $row): array
    {
        return [
            'id'          => (int) $row['id'],
            'project_id'  => (int) $row['project_id'],
            'title'       => $row['title'],
            'description' => $row['description'],
            'step_date'   => $row['step_date'],
            'is_done'     => (bool) $row['is_done'],
            'sort_order'  => (int) $row['sort_order'],
            'created_at'  => $row['created_at'],
            'updated_at'  => $row['updated_at'],
        ];
    }
}
