#pragma once
#include "fs/FileDescriptor.h"
#include "interrupts/Context.h"
#include "memory/AddressSpace.h"
#include "memory/UserHeap.h"
#include "sys/elf/Image.h"

#define TASK_MAX_FDS 32

enum class BlockReason
{
    None,
    Reading,
    Waiting,
};

struct Task
{
    enum TaskState
    {
        Idle,
        Running,
        Sleeping,
        Dying,
        Blocking,
        Exited
    };

    uint64_t id;
    uint64_t ppid;
    Context regs;

    int64_t task_sleep = 0;

    int64_t exit_status;

    int64_t task_time = 0;

    int uid;
    int euid;
    int gid;
    int egid;

    Task* next_task = nullptr;
    Task* prev_task = nullptr;

    uint64_t allocated_stack = 0;

    TaskState state;

    uint64_t cpu_time = 0;

    char floating_region[512] __attribute__((aligned(16)));
    bool floating_saved = false;

    bool user_task = true;

    bool is_user_task();

    ELFImage* image = nullptr;

    Descriptor files[TASK_MAX_FDS];

    AddressSpace address_space;

    UserHeap allocator;

    int alloc_fd();

    int alloc_fd_greater_than_or_equal(int base_fd);

    void save_context(Context* context);
    void restore_context(Context* context);

    void save_floating();
    void restore_floating();

    void switch_to_address_space();

    bool has_died();

    char name[128];

    BlockReason block_reason;

    union {
        struct
        {
            size_t size;
            int fd;
            char* buf;
        } blocking_read_info;
        struct
        {
            int64_t wait_pid;
            int* wstatus;
        } blocking_wait_info;
    };

    void resume();

    bool is_still_blocking();

    Descriptor* descriptor_from_fd(int fd, int& error);

    bool is_superuser();

  private:
    void resume_read();
    void resume_wait();

    bool is_read_still_blocking();
    bool is_wait_still_blocking();
};