use super::{
    TaskAccess, TaskError,
    input::TaskUpdateInput,
    types::{TaskItem, TaskStatus},
};

pub(super) fn validate_unblocked_status(task: &TaskItem) -> Result<(), TaskError> {
    if matches!(task.status, TaskStatus::InProgress | TaskStatus::Completed)
        && !task.blocked_by.is_empty()
    {
        return Err(TaskError::Validation(format!(
            "Task {} cannot be {} while blocked by {:?}",
            task.id, task.status, task.blocked_by
        )));
    }

    Ok(())
}

pub(super) fn validate_claimable(task: &TaskItem, owner: &str) -> Result<(), TaskError> {
    if !task.owner.is_empty() {
        return Err(TaskError::Validation(format!(
            "Task {} is already owned by '{}'",
            task.id, task.owner
        )));
    }
    if !task.blocked_by.is_empty() {
        return Err(TaskError::Validation(format!(
            "Task {} is blocked by {:?} and cannot be claimed",
            task.id, task.blocked_by
        )));
    }
    if task.status != TaskStatus::Pending {
        return Err(TaskError::Validation(format!(
            "Task {} is {} and cannot be claimed by '{}'",
            task.id, task.status, owner
        )));
    }

    Ok(())
}

pub(super) fn validate_update_access(
    task: &TaskItem,
    input: &TaskUpdateInput,
    access: TaskAccess<'_>,
) -> Result<(), TaskError> {
    match access {
        TaskAccess::Lead => Ok(()),
        TaskAccess::Teammate(name) if task.owner == name => {
            if updates_dependencies(input) {
                return Err(TaskError::Validation(format!(
                    "Teammate '{name}' cannot edit dependencies for task {}",
                    task.id
                )));
            }
            if let Some(owner) = &input.owner
                && owner != name
            {
                return Err(TaskError::Validation(format!(
                    "Teammate '{name}' cannot reassign task {} to '{}'",
                    task.id, owner
                )));
            }
            Ok(())
        }
        TaskAccess::Teammate(name) => Err(TaskError::Validation(format!(
            "Teammate '{name}' cannot update task {} owned by '{}'",
            task.id, task.owner
        ))),
    }
}

pub(super) fn is_claimable(task: &TaskItem) -> bool {
    task.status == TaskStatus::Pending && task.blocked_by.is_empty() && task.owner.is_empty()
}

pub(super) fn find_task_mut(
    tasks: &mut [TaskItem],
    task_id: u64,
) -> Result<&mut TaskItem, TaskError> {
    tasks
        .iter_mut()
        .find(|task| task.id == task_id)
        .ok_or_else(|| TaskError::Validation(format!("Task {task_id} does not exist")))
}

fn updates_dependencies(input: &TaskUpdateInput) -> bool {
    !input.add_blocked_by.is_empty()
        || !input.remove_blocked_by.is_empty()
        || !input.add_blocks.is_empty()
        || !input.remove_blocks.is_empty()
}
