#pragma once
#include "arch/CPU.h"
#include "fs/VFS.h"
#include "thread/Thread.h"
#include <bits/socket.h>

class Socket : public VFS::FileInode
{
  public:
    Socket() = default;

    VFS::InodeType type() const override
    {
        return VFS::InodeType::Socket;
    }

    void set_fs(VFS::FileSystem* fs)
    {
        m_fs = fs;
    }

    void set_inode_number(usize inum)
    {
        m_metadata.inum = inum;
    }

    VFS::FileSystem* fs() const override
    {
        return m_fs;
    }

    Result<usize> read(u8* buf, usize, usize length) const override
    {
        return recv(buf, length, 0);
    }

    Result<usize> write(const u8* buf, usize, usize length) override
    {
        return send(buf, length, 0);
    }

    virtual Result<usize> send(const u8*, usize, int) = 0;

    virtual Result<usize> recv(u8*, usize, int) const = 0;

    virtual Result<void> bind(struct sockaddr*, socklen_t) = 0;
    virtual Result<void> connect(Registers*, int, struct sockaddr*, socklen_t) = 0;

    virtual Result<SharedPtr<OpenFileDescription>> accept(Registers*, int, struct sockaddr**, socklen_t*) = 0;

    virtual Result<void> listen(int backlog) = 0;

    Result<void> truncate(usize) override
    {
        return err(EINVAL);
    }

    void did_link() override
    {
        m_metadata.nlinks++;
    }

    void did_unlink() override
    {
        m_metadata.nlinks--;
    }

    virtual bool can_accept_connections() const = 0;

    virtual bool can_read_data() const = 0;

    virtual bool peer_disconnected() const = 0;

    virtual ~Socket() = default;

  protected:
    VFS::FileSystem* m_fs { nullptr };
};