<?php
/*
 * Copyright 2026 Alessandro Chiapparini <sprint_planer_web@chiapparini.org>
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * See the LICENSE file in the project root for the full license text.
 */

declare(strict_types=1);

namespace App\Domain\Import;

/**
 * Parsed result for a single XLSX sheet (one prospective sprint).
 *
 * Pure data — no PDO, no PhpSpreadsheet. Round-trippable to/from JSON for
 * stashing in the session between the upload and the preview/commit steps.
 */
final class ParsedSheet
{
    /**
     * @param list<ParsedWeek>   $weeks
     * @param list<ParsedWorker> $workers
     * @param list<ParsedTask>   $tasks
     * @param list<string>       $warnings non-fatal observations the wizard surfaces
     */
    public function __construct(
        public readonly string  $sheetName,
        public readonly array   $weeks,
        public readonly array   $workers,
        public readonly array   $tasks,
        public readonly float   $reserveFraction,
        public readonly ?string $inferredStartDate,
        public readonly ?string $inferredEndDate,
        public readonly array   $warnings,
    ) {
    }

    /** @return array<string,mixed> */
    public function toArray(): array
    {
        return [
            'sheetName'         => $this->sheetName,
            'reserveFraction'   => $this->reserveFraction,
            'inferredStartDate' => $this->inferredStartDate,
            'inferredEndDate'   => $this->inferredEndDate,
            'warnings'          => $this->warnings,
            'weeks' => array_map(fn(ParsedWeek $w) => [
                'sortOrder'         => $w->sortOrder,
                'kw'                => $w->kw,
                'dateLabel'         => $w->dateLabel,
                'maxWorkingDays'    => $w->maxWorkingDays,
                'inferredStartDate' => $w->inferredStartDate,
            ], $this->weeks),
            'workers' => array_map(fn(ParsedWorker $p) => [
                'name'        => $p->name,
                'daysPerWeek' => $p->daysPerWeek,
                'rtb'         => $p->rtb,
            ], $this->workers),
            'tasks' => array_map(fn(ParsedTask $t) => [
                'title'     => $t->title,
                'ownerName' => $t->ownerName,
                'priority'  => $t->priority,
                'assignments' => array_map(fn(ParsedAssignment $a) => [
                    'workerName' => $a->workerName,
                    'days'       => $a->days,
                    'status'     => $a->status,
                    'argbHex'    => $a->argbHex,
                ], $t->assignments),
            ], $this->tasks),
        ];
    }

    /** @param array<string,mixed> $arr */
    public static function fromArray(array $arr): self
    {
        return new self(
            sheetName:         (string) $arr['sheetName'],
            weeks: array_map(fn($w) => new ParsedWeek(
                sortOrder:         (int)    $w['sortOrder'],
                kw:                (int)    $w['kw'],
                dateLabel:         (string) $w['dateLabel'],
                maxWorkingDays:    (int)    $w['maxWorkingDays'],
                inferredStartDate: $w['inferredStartDate'] !== null ? (string) $w['inferredStartDate'] : null,
            ), (array) ($arr['weeks'] ?? [])),
            workers: array_map(fn($w) => new ParsedWorker(
                name:        (string) $w['name'],
                daysPerWeek: array_map(fn($v) => (float) $v, (array) ($w['daysPerWeek'] ?? [])),
                rtb:         (float)  $w['rtb'],
            ), (array) ($arr['workers'] ?? [])),
            tasks: array_map(fn($t) => new ParsedTask(
                title:     (string) $t['title'],
                ownerName: $t['ownerName'] !== null ? (string) $t['ownerName'] : null,
                priority:  (int)    $t['priority'],
                assignments: array_map(fn($a) => new ParsedAssignment(
                    workerName: (string) $a['workerName'],
                    days:       (float)  $a['days'],
                    status:     (string) $a['status'],
                    argbHex:    $a['argbHex'] !== null ? (string) $a['argbHex'] : null,
                ), (array) ($t['assignments'] ?? [])),
            ), (array) ($arr['tasks'] ?? [])),
            reserveFraction:   (float) ($arr['reserveFraction']   ?? 0.2),
            inferredStartDate: $arr['inferredStartDate'] !== null ? (string) $arr['inferredStartDate'] : null,
            inferredEndDate:   $arr['inferredEndDate']   !== null ? (string) $arr['inferredEndDate']   : null,
            warnings:          array_map(fn($w) => (string) $w, (array) ($arr['warnings'] ?? [])),
        );
    }
}
