<?php

declare(strict_types=1);

require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../auth.php';

header('Content-Type: application/json; charset=utf-8');

function jsonResponse(array $data, int $status = 200): void
{
    http_response_code($status);
    header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    header('Pragma: no-cache');
    echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    exit;
}

function getInputData(): array
{
    $contentType = $_SERVER['CONTENT_TYPE'] ?? '';

    if (str_contains($contentType, 'application/json')) {
        $raw = file_get_contents('php://input');
        $data = json_decode($raw, true);

        return is_array($data) ? $data : [];
    }

    return $_POST;
}

function normalizeColor(mixed $color): string
{
    $color = trim((string)$color);

    if ($color === '') {
        return '#4ea1ff';
    }

    if (!preg_match('/^#[0-9a-fA-F]{6}$/', $color)) {
        jsonResponse([
            'success' => false,
            'error' => 'Color must be a hex color like #4ea1ff.'
        ], 400);
    }

    return strtolower($color);
}

function requireState(int $stateId, string $label = 'State'): void
{
    if ($stateId <= 0) {
        jsonResponse([
            'success' => false,
            'error' => "{$label} must be valid."
        ], 400);
    }

    $stmt = db()->prepare('SELECT id FROM task_states WHERE id = ? LIMIT 1');
    $stmt->execute([$stateId]);

    if (!$stmt->fetch()) {
        jsonResponse([
            'success' => false,
            'error' => "{$label} not found."
        ], 400);
    }
}

function requireTaskType(int $taskTypeId): void
{
    if ($taskTypeId <= 0) {
        jsonResponse([
            'success' => false,
            'error' => 'Task type must be valid.'
        ], 400);
    }

    $stmt = db()->prepare('SELECT id FROM task_types WHERE id = ? LIMIT 1');
    $stmt->execute([$taskTypeId]);

    if (!$stmt->fetch()) {
        jsonResponse([
            'success' => false,
            'error' => 'Task type not found.'
        ], 400);
    }
}

function optionResponse(array $option): array
{
    return [
        'id' => (int)$option['id'],
        'name' => $option['name'],
        'default_state' => isset($option['default_state']) && $option['default_state'] !== null
            ? (int)$option['default_state']
            : null,
        'icon' => $option['logo'] !== null
            ? 'data:image/svg+xml;base64,' . base64_encode($option['logo'])
            : null
    ];
}

function workflowData(): array
{
    $states = array_map(static function (array $state): array {
        return [
            'id' => (int)$state['id'],
            'name' => $state['name'],
            'color' => $state['color']
        ];
    }, db()->query(
        'SELECT id, name, color
         FROM task_states
         ORDER BY id ASC'
    )->fetchAll());

    $transitions = array_map(static function (array $transition): array {
        return [
            'id' => (int)$transition['id'],
            'from_id' => (int)$transition['from_id'],
            'to_id' => (int)$transition['to_id'],
            'action_name' => $transition['action_name']
        ];
    }, db()->query(
        'SELECT id, from_id, to_id, action_name
         FROM task_state_transitions
         ORDER BY id ASC'
    )->fetchAll());

    $taskTypes = array_map('optionResponse', db()->query(
        'SELECT id, name, logo, default_state
         FROM task_types
         ORDER BY id ASC'
    )->fetchAll());

    $assignments = array_map(static function (array $assignment): array {
        return [
            'id' => (int)$assignment['id'],
            'task_type' => (int)$assignment['task_type'],
            'state' => (int)$assignment['state']
        ];
    }, db()->query(
        'SELECT id, task_type, state
         FROM assigned_task_states
         ORDER BY task_type ASC, state ASC, id ASC'
    )->fetchAll());

    return [
        'states' => $states,
        'transitions' => $transitions,
        'task_types' => $taskTypes,
        'assignments' => $assignments
    ];
}

$user = requireApiAuth();
requireUserRight((int)$user['id'], 'Admin');

$api = $_GET['api'] ?? '';

switch ($api) {
    case 'WorkflowData': {
        jsonResponse([
            'success' => true,
            'workflow' => workflowData()
        ]);
    }

    case 'CreateState': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse(['success' => false, 'error' => 'CreateState requires POST.'], 405);
        }

        $data = getInputData();
        $name = trim((string)($data['name'] ?? ''));
        $color = normalizeColor($data['color'] ?? '');

        if ($name === '') {
            jsonResponse(['success' => false, 'error' => 'State name is required.'], 400);
        }

        if (strlen($name) > 128) {
            jsonResponse(['success' => false, 'error' => 'State name is too long.'], 400);
        }

        $stmt = db()->prepare('INSERT INTO task_states (name, color) VALUES (?, ?)');
        $stmt->execute([$name, $color]);

        jsonResponse([
            'success' => true,
            'state_id' => (int)db()->lastInsertId()
        ], 201);
    }

    case 'DeleteState': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse(['success' => false, 'error' => 'DeleteState requires POST.'], 405);
        }

        $stateId = (int)($_GET['state_id'] ?? 0);
        requireState($stateId);

        try {
            db()->beginTransaction();
            db()->prepare('DELETE FROM assigned_task_states WHERE state = ?')->execute([$stateId]);
            db()->prepare('DELETE FROM task_state_transitions WHERE from_id = ? OR to_id = ?')->execute([$stateId, $stateId]);
            db()->prepare('UPDATE task_types SET default_state = NULL WHERE default_state = ?')->execute([$stateId]);
            db()->prepare('DELETE FROM task_states WHERE id = ?')->execute([$stateId]);
            db()->commit();

        } catch (Throwable $e) {
            db()->rollBack();
            jsonResponse(['success' => false, 'error' => 'Could not delete state.'], 500);
        }

        jsonResponse(['success' => true, 'state_id' => $stateId]);
    }

    case 'CreateTransition': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse(['success' => false, 'error' => 'CreateTransition requires POST.'], 405);
        }

        $data = getInputData();
        $fromId = (int)($data['from_id'] ?? 0);
        $toId = (int)($data['to_id'] ?? 0);
        $actionName = trim((string)($data['action_name'] ?? ''));

        requireState($fromId, 'From state');
        requireState($toId, 'To state');

        if ($actionName === '') {
            jsonResponse(['success' => false, 'error' => 'Action name is required.'], 400);
        }

        if (strlen($actionName) > 128) {
            jsonResponse(['success' => false, 'error' => 'Action name is too long.'], 400);
        }

        $stmt = db()->prepare(
            'INSERT INTO task_state_transitions (from_id, to_id, action_name)
             VALUES (?, ?, ?)'
        );
        $stmt->execute([$fromId, $toId, $actionName]);

        jsonResponse([
            'success' => true,
            'transition_id' => (int)db()->lastInsertId()
        ], 201);
    }

    case 'DeleteTransition': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse(['success' => false, 'error' => 'DeleteTransition requires POST.'], 405);
        }

        $transitionId = (int)($_GET['transition_id'] ?? 0);

        if ($transitionId <= 0) {
            jsonResponse(['success' => false, 'error' => 'Transition must be valid.'], 400);
        }

        $stmt = db()->prepare('DELETE FROM task_state_transitions WHERE id = ?');
        $stmt->execute([$transitionId]);

        if ($stmt->rowCount() === 0) {
            jsonResponse(['success' => false, 'error' => 'Transition not found.'], 404);
        }

        jsonResponse(['success' => true, 'transition_id' => $transitionId]);
    }

    case 'AssignState': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse(['success' => false, 'error' => 'AssignState requires POST.'], 405);
        }

        $data = getInputData();
        $taskTypeId = (int)($data['task_type'] ?? 0);
        $stateId = (int)($data['state'] ?? 0);

        requireTaskType($taskTypeId);
        requireState($stateId);

        $existingStmt = db()->prepare(
            'SELECT id
             FROM assigned_task_states
             WHERE task_type = ?
               AND state = ?
             LIMIT 1'
        );
        $existingStmt->execute([$taskTypeId, $stateId]);
        $assignmentId = $existingStmt->fetchColumn();

        if (!$assignmentId) {
            $stmt = db()->prepare(
                'INSERT INTO assigned_task_states (task_type, state)
                 VALUES (?, ?)'
            );
            $stmt->execute([$taskTypeId, $stateId]);
            $assignmentId = db()->lastInsertId();
        }

        jsonResponse([
            'success' => true,
            'assignment_id' => (int)$assignmentId
        ], 201);
    }

    case 'SetDefaultState': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse(['success' => false, 'error' => 'SetDefaultState requires POST.'], 405);
        }

        $data = getInputData();
        $taskTypeId = (int)($data['task_type'] ?? 0);
        $stateId = isset($data['state']) && $data['state'] !== ''
            ? (int)$data['state']
            : null;

        requireTaskType($taskTypeId);

        if ($stateId !== null) {
            requireState($stateId);

            $assignedStmt = db()->prepare(
                'SELECT id
                 FROM assigned_task_states
                 WHERE task_type = ?
                   AND state = ?
                 LIMIT 1'
            );
            $assignedStmt->execute([$taskTypeId, $stateId]);

            if (!$assignedStmt->fetch()) {
                jsonResponse([
                    'success' => false,
                    'error' => 'Default state must be assigned to this task type.'
                ], 400);
            }
        }

        $stmt = db()->prepare(
            'UPDATE task_types
             SET default_state = ?
             WHERE id = ?'
        );
        $stmt->execute([$stateId, $taskTypeId]);

        jsonResponse([
            'success' => true,
            'task_type' => $taskTypeId,
            'default_state' => $stateId
        ]);
    }

    case 'RemoveAssignedState': {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            jsonResponse(['success' => false, 'error' => 'RemoveAssignedState requires POST.'], 405);
        }

        $assignmentId = (int)($_GET['assignment_id'] ?? 0);

        if ($assignmentId <= 0) {
            jsonResponse(['success' => false, 'error' => 'Assignment must be valid.'], 400);
        }

        $stmt = db()->prepare('DELETE FROM assigned_task_states WHERE id = ?');
        $lookupStmt = db()->prepare(
            'SELECT task_type, state
             FROM assigned_task_states
             WHERE id = ?
             LIMIT 1'
        );
        $lookupStmt->execute([$assignmentId]);
        $assignment = $lookupStmt->fetch();

        if (!$assignment) {
            jsonResponse(['success' => false, 'error' => 'Assignment not found.'], 404);
        }

        $stmt->execute([$assignmentId]);

        if ($stmt->rowCount() === 0) {
            jsonResponse(['success' => false, 'error' => 'Assignment not found.'], 404);
        }

        db()->prepare(
            'UPDATE task_types
             SET default_state = NULL
             WHERE id = ?
               AND default_state = ?'
        )->execute([
            (int)$assignment['task_type'],
            (int)$assignment['state']
        ]);

        jsonResponse(['success' => true, 'assignment_id' => $assignmentId]);
    }

    default: {
        jsonResponse([
            'success' => false,
            'error' => 'Unknown API action.'
        ], 404);
    }
}
