#pragma once

#include "fs/devices/DeviceRegistry.h"
#include <luna/String.h>
#include <luna/Types.h>

#define MBR_BOOTABLE 0x80

#define MBR_SIGNATURE_1 0x55
#define MBR_SIGNATURE_2 0xAA

namespace MBR
{
    struct [[gnu::packed]] PartitionHeader
    {
        u8 attributes;
        u8 chs_start[3];
        u8 partition_type;
        u8 chs_end[3];
        u32 start_lba;
        u32 num_sectors;
    };

    struct [[gnu::packed]] DiskHeader
    {
        u8 mbr_code[440];
        u8 disk_id[4];
        u8 reserved[2];
        PartitionHeader partitions[4];
        u8 signature[2];
    };

    class PartitionDevice : public Device
    {
      public:
        // Initializer for DeviceRegistry.
        static Result<void> create(SharedPtr<Device> host_device, usize start_block, usize num_blocks,
                                   u32 partition_index);

        Result<usize> read(u8*, usize, usize) const override;

        Result<usize> write(const u8* buf, usize offset, usize length) override;

        bool will_block_if_read() const override
        {
            return false;
        }

        bool is_block_device() const override
        {
            return true;
        }

        usize size() const override
        {
            return m_num_blocks * m_block_size;
        }

        Result<usize> block_size() const override
        {
            return m_block_size;
        }

        StringView device_path() const override
        {
            return m_device_path.view();
        }

        virtual ~PartitionDevice() = default;

      private:
        PartitionDevice() = default;
        SharedPtr<Device> m_host_device;
        usize m_block_size { 512ul };
        usize m_start_offset;
        usize m_num_blocks;
        String m_device_path;
    };

    static_assert(sizeof(DiskHeader) == 512ul);

    Result<bool> identify(SharedPtr<Device> device);
};