<?php
/**
 * Task Mapper
 *
 * PHP version 8.2+
 *
 * Maps between Task domain objects and FrontMatterDocument representations.
 *
 * @category Support
 * @package  IronKanban\Support
 * @author   Keith Solomon <keith@keithsolomon.net>
 * @license  Unlicense https://unlicense.org
 * @link     https://git.keithsolomon.net/keith/IronKanban
 */

declare(strict_types=1);

namespace IronKanban\Support;

use IronKanban\Domain\Task;
use IronKanban\Markdown\FrontMatterDocument;

/**
 * TaskMapper maps Task objects and FrontMatterDocument representations
 *
 * @category Support
 * @package  IronKanban\Support
 * @author   Keith Solomon <keith@keithsolomon.net>
 * @license  Unlicense https://unlicense.org
 * @link     https://git.keithsolomon.net/keith/IronKanban
 */
class TaskMapper {
    /**
     * Convert a FrontMatterDocument to a Task domain object
     *
     * @param string              $projectId The project identifier
     * @param string              $fileName  The task file name
     * @param FrontMatterDocument $document  The front matter document
     *
     * @return Task The mapped task
     */
    public function fromDocument(
        string $projectId,
        string $fileName,
        FrontMatterDocument $document
    ): Task {
        $meta = $document->meta;

        $id = (string) ($meta['id'] ?? pathinfo($fileName, PATHINFO_FILENAME));
        $title = (string) ($meta['title'] ?? $id);

        $column = isset($meta['column'])
            ? $this->normalizeColumn((string) $meta['column'])
            : $this->mapLegacySectionToColumn(
                (string) ($meta['section'] ?? 'backlog')
            );

        $order = isset($meta['order']) ? (int) $meta['order'] : 100;
        $completed = (bool) ($meta['completed'] ?? false);
        $priority = (string) ($meta['priority'] ?? 'normal');
        $isActive = (bool) ($meta['is_active'] ?? true);

        return new Task(
            id: $id,
            title: $title,
            projectId: (string) ($meta['project_id'] ?? $projectId),
            column: $column,
            order: $order,
            completed: $completed,
            priority: $priority,
            isActive: $isActive,
            body: $document->body,
            fileName: $fileName,
            meta: $meta
        );
    }

    /**
     * Convert a Task domain object to a FrontMatterDocument
     *
     * @param Task $task The task to convert
     *
     * @return FrontMatterDocument The mapped document
     */
    public function toDocument(Task $task): FrontMatterDocument {
        $meta = $task->meta;

        $meta['id'] = $task->id;
        $meta['type'] = 'task';
        $meta['title'] = $task->title;
        $meta['project_id'] = $task->projectId;
        $meta['column'] = $task->column;
        $meta['order'] = $task->order;
        $meta['completed'] = $task->completed;
        $meta['priority'] = $task->priority;
        $meta['is_active'] = $task->isActive;

        if (!isset($meta['created']) || trim((string) $meta['created']) === '') {
            $meta['created'] = gmdate('c');
        }

        $meta['updated'] = gmdate('c');

        return new FrontMatterDocument($meta, $task->body);
    }

    /**
     * Normalize a column name
     *
     * @param string $column The column name to normalize
     *
     * @return string The normalized column name
     */
    public function normalizeColumn(string $column): string {
        $column = trim(strtolower($column));

        if ($column === '') {
            return 'backlog';
        }

        $column = preg_replace('/[^a-z0-9]+/', '-', $column) ?? 'backlog';
        $column = trim($column, '-');

        return $column !== '' ? $column : 'backlog';
    }

    /**
     * Map a legacy section name to a modern column name
     *
     * @param string $section The legacy section name
     *
     * @return string The normalized column name
     */
    public function mapLegacySectionToColumn(string $section): string {
        return $this->normalizeColumn($section);
    }
}
