#include "xbox_ref_bridge.h"

#include <string.h>

void xbox_ref_dump_result_init(xbox_ref_dump_result *result)
{
    if (result)
        memset(result, 0, sizeof(*result));
}

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <winioctl.h>
#include <ntddscsi.h>
#include <stdio.h>
#include <stddef.h>
#include <io.h>
#include "xbox_ref/utils.h"
#include "xbox_ref/sha1.h"
#include "xbox_ref/unlock.h"
#include "xbox_ref/xbox_ref_log.h"

#define printf xbox_ref_printf

#define XBOX_REF_LOCKED_VIDEO_VIEW_MAX_SECTORS 200000U

static BOOL xbox_ref_capacity_is_game_view(uint32_t sectors)
{
    return sectors > XBOX_REF_LOCKED_VIDEO_VIEW_MAX_SECTORS;
}

static BOOL xbox_ref_capacity_is_xgd1_locked_view(uint32_t sectors)
{
    return sectors == XGD1_VIDEO_TOTAL_SECTORS;
}

static BOOL xbox_ref_capacity_is_xgd1_game_view(uint32_t sectors)
{
    return sectors == REDUMP_SECTORS;
}

static uint32_t xbox_ref_refresh_ready_capacity(HANDLE hDevice)
{
    RefreshVolume(hDevice);
    Sleep(2000);
    EnsureDriveReady(hDevice, 30000);
    return GetTotalSectors(hDevice);
}

static char xbox_ref_drive_letter_from_device(const char *device)
{
    if (!device || !device[0]) return 0;
    if (device[0] && device[1] == ':') return device[0];
    if (device[0] == '\\' && device[1] == '\\' && device[2] == '.' && device[3] == '\\' && device[4] && device[5] == ':') return device[4];
    return device[0];
}

#define XGD1_LAYOUT_PROBE_SCHEMA_VERSION 1
#define XGD1_LAYOUT_PROBE_SECTOR_BYTES 2048U
#define XGD1_LAYOUT_PROBE_MAX_SAMPLES 20U

typedef struct xbox_ref_probe_read_s
{
    int read_ok;
    DWORD win32_error;
    UCHAR scsi_status;
    UCHAR sense_key;
    UCHAR asc;
    UCHAR ascq;
    uint32_t nonzero_bytes;
    int all_zero;
    char sha1[41];
    unsigned char data[XGD1_LAYOUT_PROBE_SECTOR_BYTES];
} xbox_ref_probe_read;

typedef struct xbox_ref_probe_sample_s
{
    uint32_t lba;
    const char *label;
    xbox_ref_probe_read read10;
    xbox_ref_probe_read read12;
} xbox_ref_probe_sample;

typedef struct xbox_ref_probe_state_s
{
    const char *name;
    uint32_t capacity;
    int capacity_valid;
    int state_verified;
    uint32_t sample_count;
    xbox_ref_probe_sample samples[XGD1_LAYOUT_PROBE_MAX_SAMPLES];
} xbox_ref_probe_state;

typedef struct xbox_ref_probe_point_s
{
    uint32_t lba;
    const char *label;
} xbox_ref_probe_point;

typedef struct xbox_ref_sptd_with_sense_s
{
    SCSI_PASS_THROUGH_DIRECT sptd;
    ULONG filler;
    UCHAR sense[32];
} xbox_ref_sptd_with_sense;

static const xbox_ref_probe_point xbox_ref_locked_probe_points[] = {
    {0U, "locked_logical_start"},
    {31U, "locked_early_lba_31"},
    {32U, "locked_early_lba_32"},
    {XGD1_VIDEO_L0_SECTORS - 1U, "video_l0_last"},
    {XGD1_VIDEO_L0_SECTORS, "locked_video_l1_first"},
    {XGD1_VIDEO_TOTAL_SECTORS - 1U, "locked_video_last"},
    {XGD1_VIDEO_TOTAL_SECTORS, "locked_capacity_plus_one"},
    {XGD1_GAME_OUTPUT_START_LBA - 1U, "pregame_output_last"},
    {XGD1_GAME_OUTPUT_START_LBA, "game_output_start"},
    {XGD1_REDUMP_LAYER_BREAK_LBA - 1U, "output_layer_break_minus_one"},
    {XGD1_REDUMP_LAYER_BREAK_LBA, "output_layer_break"},
    {XGD1_VIDEO_L1_OUTPUT_START_LBA - 1U, "postgame_output_last"},
    {XGD1_VIDEO_L1_OUTPUT_START_LBA, "video_l1_output_start"},
    {XGD1_FULL_REDUMP_SECTORS - 1U, "full_output_last"}
};

static const xbox_ref_probe_point xbox_ref_unlocked_probe_points[] = {
    {0U, "unlocked_source_start"},
    {XGD1_XISO_LEADIN_SECTORS - 1U, "unlocked_source_leadin_last"},
    {XGD1_GAME_SOURCE_START_LBA, "xdfs_source_start"},
    {XGD1_GAME_SOURCE_START_LBA + 1U, "xdfs_source_next"},
    {(XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS) - 1U, "synthetic_gap_length_minus_one"},
    {XGD1_GAME_OUTPUT_START_LBA - XGD1_VIDEO_L0_SECTORS, "synthetic_gap_length"},
    {XGD1_GAME_OUTPUT_START_LBA - 1U, "pregame_output_last_as_unlocked_source"},
    {XGD1_GAME_OUTPUT_START_LBA, "game_output_start_as_unlocked_source"},
    {(XGD1_REDUMP_LAYER_BREAK_LBA - XGD1_GAME_OUTPUT_START_LBA) - 1U, "mapped_layer_break_source_minus_one"},
    {XGD1_REDUMP_LAYER_BREAK_LBA - XGD1_GAME_OUTPUT_START_LBA, "mapped_layer_break_source"},
    {XGD1_GAME_SOURCE_START_LBA + XGD1_GAME_SOURCE_SECTORS - 1U, "unlocked_source_last"},
    {REDUMP_SECTORS, "unlocked_capacity_plus_one"},
    {XGD1_GAME_OUTPUT_START_LBA + REDUMP_SECTORS, "postgame_output_start_as_unlocked_source"},
    {XGD1_VIDEO_L1_OUTPUT_START_LBA, "video_l1_output_start_as_unlocked_source"}
};

static void xbox_ref_probe_parse_sense(const UCHAR *sense,
                                       UCHAR *sense_key,
                                       UCHAR *asc,
                                       UCHAR *ascq)
{
    UCHAR response;

    if (sense_key) *sense_key = 0;
    if (asc) *asc = 0;
    if (ascq) *ascq = 0;
    if (!sense)
        return;

    response = (UCHAR)(sense[0] & 0x7f);
    if (response == 0x70 || response == 0x71)
    {
        if (sense_key) *sense_key = (UCHAR)(sense[2] & 0x0f);
        if (asc) *asc = sense[12];
        if (ascq) *ascq = sense[13];
    }
    else if (response == 0x72 || response == 0x73)
    {
        if (sense_key) *sense_key = (UCHAR)(sense[1] & 0x0f);
        if (asc) *asc = sense[2];
        if (ascq) *ascq = sense[3];
    }
}

static void xbox_ref_probe_sha1(const unsigned char *data,
                                uint32_t data_size,
                                char out_sha1[41])
{
    SHA1_CTX ctx;
    unsigned char digest[20];
    uint32_t i;

    if (!out_sha1)
        return;
    out_sha1[0] = '\0';
    if (!data || data_size == 0)
        return;

    SHA1_Init(&ctx);
    SHA1_Update(&ctx, data, data_size);
    SHA1_Final(digest, &ctx);

    for (i = 0; i < 20U; ++i)
        sprintf(out_sha1 + (i * 2U), "%02x", digest[i]);
    out_sha1[40] = '\0';
}

static void xbox_ref_probe_read_one(HANDLE hDevice,
                                    UCHAR opcode,
                                    uint32_t lba,
                                    xbox_ref_probe_read *result)
{
    xbox_ref_sptd_with_sense packet;
    unsigned char *buffer;
    DWORD bytes_returned;
    BOOL ioctl_ok;
    uint32_t i;

    if (!result)
        return;
    memset(result, 0, sizeof(*result));

    buffer = (unsigned char *)VirtualAlloc(NULL,
                                           XGD1_LAYOUT_PROBE_SECTOR_BYTES,
                                           MEM_COMMIT | MEM_RESERVE,
                                           PAGE_READWRITE);
    if (!buffer)
    {
        result->win32_error = ERROR_NOT_ENOUGH_MEMORY;
        return;
    }

    memset(buffer, 0, XGD1_LAYOUT_PROBE_SECTOR_BYTES);
    memset(&packet, 0, sizeof(packet));

    packet.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
    packet.sptd.CdbLength = (opcode == 0xA8) ? 12 : 10;
    packet.sptd.SenseInfoLength = sizeof(packet.sense);
    packet.sptd.DataIn = SCSI_IOCTL_DATA_IN;
    packet.sptd.DataTransferLength = XGD1_LAYOUT_PROBE_SECTOR_BYTES;
    packet.sptd.TimeOutValue = 10;
    packet.sptd.DataBuffer = buffer;
    packet.sptd.SenseInfoOffset = offsetof(xbox_ref_sptd_with_sense, sense);
    packet.sptd.Cdb[0] = opcode;
    packet.sptd.Cdb[2] = (UCHAR)((lba >> 24) & 0xff);
    packet.sptd.Cdb[3] = (UCHAR)((lba >> 16) & 0xff);
    packet.sptd.Cdb[4] = (UCHAR)((lba >> 8) & 0xff);
    packet.sptd.Cdb[5] = (UCHAR)(lba & 0xff);

    if (opcode == 0xA8)
    {
        packet.sptd.Cdb[9] = 1;
    }
    else
    {
        packet.sptd.Cdb[8] = 1;
    }

    bytes_returned = 0;
    ioctl_ok = DeviceIoControl(hDevice,
                               IOCTL_SCSI_PASS_THROUGH_DIRECT,
                               &packet,
                               sizeof(packet),
                               &packet,
                               sizeof(packet),
                               &bytes_returned,
                               NULL);

    result->win32_error = ioctl_ok ? ERROR_SUCCESS : GetLastError();
    result->scsi_status = packet.sptd.ScsiStatus;
    xbox_ref_probe_parse_sense(packet.sense,
                               &result->sense_key,
                               &result->asc,
                               &result->ascq);
    result->read_ok = (ioctl_ok && packet.sptd.ScsiStatus == 0) ? 1 : 0;

    if (result->read_ok)
    {
        memcpy(result->data, buffer, XGD1_LAYOUT_PROBE_SECTOR_BYTES);
        result->nonzero_bytes = 0;
        for (i = 0; i < XGD1_LAYOUT_PROBE_SECTOR_BYTES; ++i)
        {
            if (buffer[i] != 0)
                result->nonzero_bytes++;
        }
        result->all_zero = (result->nonzero_bytes == 0U) ? 1 : 0;
        xbox_ref_probe_sha1(buffer,
                            XGD1_LAYOUT_PROBE_SECTOR_BYTES,
                            result->sha1);
    }

    VirtualFree(buffer, 0, MEM_RELEASE);
}

static void xbox_ref_probe_capture_state(HANDLE hDevice,
                                         xbox_ref_probe_state *state,
                                         const xbox_ref_probe_point *points,
                                         uint32_t point_count)
{
    uint32_t i;

    if (!state || !points)
        return;

    if (point_count > XGD1_LAYOUT_PROBE_MAX_SAMPLES)
        point_count = XGD1_LAYOUT_PROBE_MAX_SAMPLES;

    state->sample_count = point_count;
    for (i = 0; i < point_count; ++i)
    {
        state->samples[i].lba = points[i].lba;
        state->samples[i].label = points[i].label;

        printf("[XGD1-PROBE] %s: probing LBA %u (%s) with READ(10) and READ(12).\n",
               state->name ? state->name : "state",
               points[i].lba,
               points[i].label ? points[i].label : "unlabeled");

        xbox_ref_probe_read_one(hDevice,
                                0x28,
                                points[i].lba,
                                &state->samples[i].read10);
        xbox_ref_probe_read_one(hDevice,
                                0xA8,
                                points[i].lba,
                                &state->samples[i].read12);
    }
}

static void xbox_ref_probe_json_string(FILE *json, const char *value)
{
    const unsigned char *p;

    if (!json)
        return;
    if (!value)
        value = "";

    fputc('"', json);
    p = (const unsigned char *)value;
    while (*p)
    {
        switch (*p)
        {
            case '\\': fputs("\\\\", json); break;
            case '"': fputs("\\\"", json); break;
            case '\b': fputs("\\b", json); break;
            case '\f': fputs("\\f", json); break;
            case '\n': fputs("\\n", json); break;
            case '\r': fputs("\\r", json); break;
            case '\t': fputs("\\t", json); break;
            default:
                if (*p < 0x20)
                    fprintf(json, "\\u%04x", (unsigned int)*p);
                else
                    fputc(*p, json);
                break;
        }
        ++p;
    }
    fputc('"', json);
}

static void xbox_ref_probe_json_hex(FILE *json,
                                    const unsigned char *data,
                                    uint32_t data_size)
{
    uint32_t i;

    if (!json)
        return;
    fputc('"', json);
    if (data)
    {
        for (i = 0; i < data_size; ++i)
            fprintf(json, "%02x", data[i]);
    }
    fputc('"', json);
}

static void xbox_ref_probe_write_cdb(FILE *json,
                                      UCHAR opcode,
                                      uint32_t lba)
{
    if (!json)
        return;

    if (opcode == 0xA8)
    {
        fprintf(json,
                "\"a800%08x000000010000\"",
                lba);
    }
    else
    {
        fprintf(json,
                "\"2800%08x00000100\"",
                lba);
    }
}

static void xbox_ref_probe_write_read(FILE *json,
                                      const char *indent,
                                      const char *name,
                                      const xbox_ref_probe_read *read)
{
    if (!json || !read)
        return;

    fprintf(json, "%s", indent);
    xbox_ref_probe_json_string(json, name);
    fprintf(json, ": {\n");
    fprintf(json, "%s  \"read_ok\": %s,\n", indent, read->read_ok ? "true" : "false");
    fprintf(json, "%s  \"win32_error\": %lu,\n", indent, (unsigned long)read->win32_error);
    fprintf(json, "%s  \"scsi_status\": %u,\n", indent, (unsigned int)read->scsi_status);
    fprintf(json, "%s  \"sense_key\": %u,\n", indent, (unsigned int)read->sense_key);
    fprintf(json, "%s  \"asc\": %u,\n", indent, (unsigned int)read->asc);
    fprintf(json, "%s  \"ascq\": %u,\n", indent, (unsigned int)read->ascq);
    if (read->read_ok)
    {
        fprintf(json, "%s  \"nonzero_bytes\": %u,\n", indent, read->nonzero_bytes);
        fprintf(json, "%s  \"all_zero\": %s,\n", indent, read->all_zero ? "true" : "false");
    }
    else
    {
        fprintf(json, "%s  \"nonzero_bytes\": null,\n", indent);
        fprintf(json, "%s  \"all_zero\": null,\n", indent);
    }
    fprintf(json, "%s  \"sha1\": ", indent);
    if (read->read_ok)
        xbox_ref_probe_json_string(json, read->sha1);
    else
        fprintf(json, "null");
    fprintf(json, ",\n");
    fprintf(json, "%s  \"data_hex\": ", indent);
    if (read->read_ok)
        xbox_ref_probe_json_hex(json, read->data, XGD1_LAYOUT_PROBE_SECTOR_BYTES);
    else
        xbox_ref_probe_json_string(json, "");
    fprintf(json, "\n%s}", indent);
}

static void xbox_ref_probe_write_state(FILE *json,
                                       const xbox_ref_probe_state *state,
                                       int trailing_comma)
{
    uint32_t i;

    fprintf(json, "    {\n");
    fprintf(json, "      \"name\": ");
    xbox_ref_probe_json_string(json, state->name);
    fprintf(json, ",\n");
    fprintf(json, "      \"capacity_valid\": %s,\n", state->capacity_valid ? "true" : "false");
    fprintf(json, "      \"capacity_sectors\": %u,\n", state->capacity);
    fprintf(json, "      \"state_verified\": %s,\n", state->state_verified ? "true" : "false");
    fprintf(json, "      \"samples\": [\n");

    for (i = 0; i < state->sample_count; ++i)
    {
        const xbox_ref_probe_sample *sample = &state->samples[i];
        int identical = 0;

        if (sample->read10.read_ok && sample->read12.read_ok)
        {
            identical = (memcmp(sample->read10.data,
                                sample->read12.data,
                                XGD1_LAYOUT_PROBE_SECTOR_BYTES) == 0) ? 1 : 0;
        }

        fprintf(json, "        {\n");
        fprintf(json, "          \"lba\": %u,\n", sample->lba);
        fprintf(json, "          \"label\": ");
        xbox_ref_probe_json_string(json, sample->label);
        fprintf(json, ",\n");
        fprintf(json, "          \"read10_cdb_hex\": ");
        xbox_ref_probe_write_cdb(json, 0x28, sample->lba);
        fprintf(json, ",\n");
        fprintf(json, "          \"read12_cdb_hex\": ");
        xbox_ref_probe_write_cdb(json, 0xA8, sample->lba);
        fprintf(json, ",\n");
        xbox_ref_probe_write_read(json, "          ", "read10", &sample->read10);
        fprintf(json, ",\n");
        xbox_ref_probe_write_read(json, "          ", "read12", &sample->read12);
        fprintf(json, ",\n");
        fprintf(json,
                "          \"read10_read12_comparable\": %s,\n",
                (sample->read10.read_ok && sample->read12.read_ok) ? "true" : "false");
        fprintf(json, "          \"read10_read12_identical\": ");
        if (sample->read10.read_ok && sample->read12.read_ok)
            fprintf(json, "%s\n", identical ? "true" : "false");
        else
            fprintf(json, "null\n");
        fprintf(json, "        }%s\n", (i + 1U < state->sample_count) ? "," : "");
    }

    fprintf(json, "      ]\n");
    fprintf(json, "    }%s\n", trailing_comma ? "," : "");
}

static BOOL xbox_ref_probe_write_report(const char *report_path,
                                        const char *device,
                                        uint32_t entry_capacity,
                                        int entry_game_view,
                                        int volume_lock_acquired,
                                        const xbox_ref_probe_state *locked_state,
                                        const xbox_ref_probe_state *unlocked_state,
                                        int restore_attempted,
                                        uint32_t restored_capacity,
                                        int restore_verified)
{
    char tmp_path[XBOX_REF_RESULT_PATH_MAX];
    const char *final_path;
    FILE *json;
    int fd;
    BOOL moved;

    final_path = (report_path && report_path[0]) ? report_path : "xgd1_layout_probe.json";
    {
        int path_length = snprintf(tmp_path,
                                   sizeof(tmp_path),
                                   "%s.tmp.%lu",
                                   final_path,
                                   (unsigned long)GetCurrentProcessId());
        if (path_length < 0 || (size_t)path_length >= sizeof(tmp_path))
        {
            printf("[XGD1-PROBE] Fatal: report path is too long.\n");
            return FALSE;
        }
    }

    json = fopen(tmp_path, "wb");
    if (!json)
    {
        printf("[XGD1-PROBE] Fatal: could not create temporary report %s.\n", tmp_path);
        return FALSE;
    }

    fprintf(json, "{\n");
    fprintf(json, "  \"schema_version\": %d,\n", XGD1_LAYOUT_PROBE_SCHEMA_VERSION);
    fprintf(json, "  \"producer\": \"friidump-0.5.3.11\",\n");
    fprintf(json, "  \"probe\": \"original_xbox_xgd1_logical_layout_boundary\",\n");
    fprintf(json, "  \"device\": ");
    xbox_ref_probe_json_string(json, device ? device : "");
    fprintf(json, ",\n");
    fprintf(json, "  \"safety\": {\n");
    fprintf(json, "    \"read_only_sector_commands\": true,\n");
    fprintf(json, "    \"authentication_handshake_used\": true,\n");
    fprintf(json, "    \"tray_cycle_used\": true,\n");
    fprintf(json, "    \"firmware_write_used\": false,\n");
    fprintf(json, "    \"flash_command_used\": false\n");
    fprintf(json, "  },\n");
    fprintf(json, "  \"constants\": {\n");
    fprintf(json, "    \"full_output_sectors\": %u,\n", XGD1_FULL_REDUMP_SECTORS);
    fprintf(json, "    \"game_output_start_lba\": %u,\n", XGD1_GAME_OUTPUT_START_LBA);
    fprintf(json, "    \"game_view_sectors\": %u,\n", REDUMP_SECTORS);
    fprintf(json, "    \"video_total_sectors\": %u,\n", XGD1_VIDEO_TOTAL_SECTORS);
    fprintf(json, "    \"video_l0_sectors\": %u,\n", XGD1_VIDEO_L0_SECTORS);
    fprintf(json, "    \"video_l1_sectors\": %u,\n", XGD1_VIDEO_L1_SECTORS);
    fprintf(json, "    \"video_l1_output_start_lba\": %u,\n", XGD1_VIDEO_L1_OUTPUT_START_LBA);
    fprintf(json, "    \"output_layer_break_lba\": %u\n", XGD1_REDUMP_LAYER_BREAK_LBA);
    fprintf(json, "  },\n");
    fprintf(json, "  \"entry\": {\n");
    fprintf(json, "    \"capacity_sectors\": %u,\n", entry_capacity);
    fprintf(json, "    \"game_view\": %s,\n", entry_game_view ? "true" : "false");
    fprintf(json, "    \"classification\": ");
    if (xbox_ref_capacity_is_xgd1_game_view(entry_capacity))
        xbox_ref_probe_json_string(json, "unlocked_game");
    else if (xbox_ref_capacity_is_xgd1_locked_view(entry_capacity))
        xbox_ref_probe_json_string(json, "locked_video");
    else
        xbox_ref_probe_json_string(json, "other_or_unknown");
    fprintf(json, "\n");
    fprintf(json, "  },\n");
    fprintf(json, "  \"volume_lock_acquired_at_least_once\": %s,\n", volume_lock_acquired ? "true" : "false");
    fprintf(json,
            "  \"required_states_verified\": %s,\n",
            (locked_state->state_verified && unlocked_state->state_verified) ? "true" : "false");
    fprintf(json, "  \"states\": [\n");
    xbox_ref_probe_write_state(json, locked_state, 1);
    xbox_ref_probe_write_state(json, unlocked_state, 0);
    fprintf(json, "  ],\n");
    fprintf(json, "  \"restoration\": {\n");
    fprintf(json, "    \"attempted\": %s,\n", restore_attempted ? "true" : "false");
    fprintf(json, "    \"capacity_sectors\": %u,\n", restored_capacity);
    fprintf(json, "    \"verified\": %s\n", restore_verified ? "true" : "false");
    fprintf(json, "  },\n");
    fprintf(json, "  \"interpretation_boundary\": {\n");
    fprintf(json, "    \"pregame_padding_resolved\": false,\n");
    fprintf(json, "    \"postgame_padding_resolved\": false,\n");
    fprintf(json, "    \"game_leadin_resolved\": false,\n");
    fprintf(json, "    \"note\": \"This report records ordinary logical READ(10)/READ(12) behavior in locked/video and unlocked/game states. It does not claim that inaccessible physical filler sectors are zero or that the current reconstructed image is Redump-exact.\"\n");
    fprintf(json, "  }\n");
    fprintf(json, "}\n");

    if (fflush(json) != 0)
    {
        fclose(json);
        DeleteFileA(tmp_path);
        return FALSE;
    }

    fd = _fileno(json);
    if (fd < 0 || _commit(fd) != 0)
    {
        fclose(json);
        DeleteFileA(tmp_path);
        return FALSE;
    }

    if (fclose(json) != 0)
    {
        DeleteFileA(tmp_path);
        return FALSE;
    }

    moved = MoveFileExA(tmp_path,
                        final_path,
                        MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
    if (!moved)
    {
        printf("[XGD1-PROBE] Fatal: could not atomically publish report %s (error %lu).\n",
               final_path,
               (unsigned long)GetLastError());
        DeleteFileA(tmp_path);
        return FALSE;
    }

    printf("[XGD1-PROBE] Atomic report written: %s\n", final_path);
    return TRUE;
}

static int xbox_ref_xgd1_layout_probe_core(HANDLE hDevice,
                                            const char *device,
                                            const char *report_path,
                                            BOOL owns_handle)
{
    xbox_ref_probe_state locked_state;
    xbox_ref_probe_state unlocked_state;
    uint32_t entry_capacity;
    uint32_t restored_capacity;
    int entry_game_view;
    int volume_lock_acquired;
    int volume_lock_ever;
    int restore_attempted;
    int restore_verified;
    int states_verified;
    DWORD bytes_returned;
    BOOL report_ok;

    memset(&locked_state, 0, sizeof(locked_state));
    memset(&unlocked_state, 0, sizeof(unlocked_state));
    locked_state.name = "locked_video";
    unlocked_state.name = "unlocked_game";
    entry_capacity = 0;
    restored_capacity = 0;
    entry_game_view = 0;
    volume_lock_acquired = 0;
    volume_lock_ever = 0;
    restore_attempted = 0;
    restore_verified = 0;
    states_verified = 0;
    bytes_returned = 0;

    xbox_ref_log_open_for_target(report_path, xbox_ref_drive_letter_from_device(device));
    printf("[XGD1-PROBE] Starting read-only logical layout boundary probe.\n");
    printf("[XGD1-PROBE] The existing XGD1 output layout will not be modified.\n");

    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL)
    {
        printf("[XGD1-PROBE] Fatal: invalid drive handle.\n");
        if (owns_handle)
            xbox_ref_log_close();
        return 1;
    }

    if (!EnsureDriveReady(hDevice, 30000))
    {
        printf("[XGD1-PROBE] Fatal: media did not become ready.\n");
        if (owns_handle)
            xbox_ref_log_close();
        return 1;
    }

    entry_capacity = GetTotalSectors(hDevice);
    entry_game_view = xbox_ref_capacity_is_xgd1_game_view(entry_capacity) ? 1 : 0;
    printf("[XGD1-PROBE] Entry READ CAPACITY: %u sectors (%s).\n",
           entry_capacity,
           entry_game_view ? "game view" : "locked/video or unknown view");

    DeviceIoControl(hDevice,
                    FSCTL_UNLOCK_VOLUME,
                    NULL,
                    0,
                    NULL,
                    0,
                    &bytes_returned,
                    NULL);

    printf("[XGD1-PROBE] Cycling tray to establish locked/video view.\n");
    AutomateTrayCycle(hDevice);
    locked_state.capacity = xbox_ref_refresh_ready_capacity(hDevice);
    locked_state.capacity_valid = locked_state.capacity != 0U;
    locked_state.state_verified = (locked_state.capacity_valid &&
                                   xbox_ref_capacity_is_xgd1_locked_view(locked_state.capacity)) ? 1 : 0;
    printf("[XGD1-PROBE] Locked/video READ CAPACITY: %u sectors; verified=%s.\n",
           locked_state.capacity,
           locked_state.state_verified ? "yes" : "no");

    if (DeviceIoControl(hDevice,
                        FSCTL_LOCK_VOLUME,
                        NULL,
                        0,
                        NULL,
                        0,
                        &bytes_returned,
                        NULL))
    {
        volume_lock_acquired = 1;
        volume_lock_ever = 1;
        printf("[XGD1-PROBE] Windows volume lock acquired.\n");
    }
    else
    {
        printf("[XGD1-PROBE][WARN] Windows volume lock was not acquired; close AutoPlay and Explorer dialogs if results are unstable.\n");
    }

    SetDriveSpeedMax(hDevice);
    xbox_ref_probe_capture_state(hDevice,
                                 &locked_state,
                                 xbox_ref_locked_probe_points,
                                 (uint32_t)(sizeof(xbox_ref_locked_probe_points) /
                                            sizeof(xbox_ref_locked_probe_points[0])));

    printf("[XGD1-PROBE] Applying the full Xbox handshake to establish game view.\n");
    UnlockDrive(hDevice);
    unlocked_state.capacity = xbox_ref_refresh_ready_capacity(hDevice);
    unlocked_state.capacity_valid = unlocked_state.capacity != 0U;
    unlocked_state.state_verified = (unlocked_state.capacity_valid &&
                                     xbox_ref_capacity_is_xgd1_game_view(unlocked_state.capacity)) ? 1 : 0;
    printf("[XGD1-PROBE] Unlocked/game READ CAPACITY: %u sectors; verified=%s.\n",
           unlocked_state.capacity,
           unlocked_state.state_verified ? "yes" : "no");

    xbox_ref_probe_capture_state(hDevice,
                                 &unlocked_state,
                                 xbox_ref_unlocked_probe_points,
                                 (uint32_t)(sizeof(xbox_ref_unlocked_probe_points) /
                                            sizeof(xbox_ref_unlocked_probe_points[0])));

    if (volume_lock_acquired)
    {
        DeviceIoControl(hDevice,
                        FSCTL_UNLOCK_VOLUME,
                        NULL,
                        0,
                        NULL,
                        0,
                        &bytes_returned,
                        NULL);
        volume_lock_acquired = 0;
    }

    if (!entry_game_view && entry_capacity != 0U)
    {
        restore_attempted = 1;
        printf("[XGD1-PROBE] Restoring the entry locked/video state with a final tray cycle.\n");
        AutomateTrayCycle(hDevice);
        restored_capacity = xbox_ref_refresh_ready_capacity(hDevice);
        restore_verified = (restored_capacity != 0U &&
                            xbox_ref_capacity_is_xgd1_locked_view(restored_capacity)) ? 1 : 0;
    }
    else
    {
        restored_capacity = GetTotalSectors(hDevice);
        restore_verified = (entry_game_view &&
                            xbox_ref_capacity_is_xgd1_game_view(restored_capacity)) ? 1 : 0;
    }

    states_verified = (locked_state.state_verified &&
                       unlocked_state.state_verified) ? 1 : 0;

    report_ok = xbox_ref_probe_write_report(report_path,
                                             device,
                                             entry_capacity,
                                             entry_game_view,
                                             volume_lock_ever,
                                             &locked_state,
                                             &unlocked_state,
                                             restore_attempted,
                                             restored_capacity,
                                             restore_verified);

    if (owns_handle)
    {
        printf("[XGD1-PROBE] Issuing STOP UNIT / spin-down after probe... ");
        printf("%s\n", StopDriveUnit(hDevice) ? "OK" : "FAILED");
        CloseDrive(hDevice);
        xbox_ref_log_close();
    }

    if (!report_ok)
        return 1;
    if (!states_verified)
    {
        printf("[XGD1-PROBE] Probe report is partial because one or more drive states were not verified.\n");
        return 1;
    }

    printf("[XGD1-PROBE] Probe complete. Synthetic ranges remain unresolved until the captured evidence supports a source mapping.\n");
    return 0;
}


static int xbox_ref_gdr8050l_dump_core(HANDLE hDevice, const char *device, const char *filename, char mode, BOOL ownsHandle, xbox_ref_dump_result *result)
{
    char driveLetter;
    XboxGameInfo game;
    BOOL isDualLayer = FALSE;
    bool isDualLayerBool = false;
    char mediaId[33] = {0};
    char finalFilename[MAX_PATH] = {0};
    BOOL filenameOverride;
    uint32_t totalSectors = 0;
    DWORD dwBytesReturned = 0;
    BOOL volumeLocked = FALSE;
    BOOL ok = FALSE;

    xbox_ref_dump_result_init(result);
    if (result) {
        result->attempted = 1;
        result->mode = mode;
    }

    filenameOverride = (filename && filename[0]);

    if (mode != '1' && mode != '2') {
        xbox_ref_log_open_for_target(filename, 0);
        printf("[XBOX-REF] Fatal: unsupported Xbox reference dump mode '%c'.\n", mode);
        if (ownsHandle)
            xbox_ref_log_close();
        return 1;
    }

    driveLetter = xbox_ref_drive_letter_from_device(device);
    if (!driveLetter) {
        xbox_ref_log_open_for_target(filename, 0);
        printf("[XBOX-REF] Fatal: could not parse drive letter from device '%s'.\n", device ? device : "(null)");
        if (ownsHandle)
            xbox_ref_log_close();
        return 1;
    }

    xbox_ref_log_open_for_target(filename, driveLetter);
    printf("[XBOX-REF] Using copied original GDR-8050L dumper flow for drive %c:.\n", driveLetter);
    printf("[XBOX-REF] Handle mode: %s.\n", ownsHandle ? "opened by xbox_ref wrapper" : "using FriiDump's existing drive HANDLE");
    printf("[XBOX-REF] Preserving reference timing sleeps: tray 3000ms, ready-settle 1500ms/10000ms fallback, RefreshVolume 1000ms + post-refresh 2000ms.\n");

    if (hDevice == INVALID_HANDLE_VALUE || hDevice == NULL) {
        printf("[XBOX-REF] Fatal: invalid drive handle for %c:.\n", driveLetter);
        goto cleanup;
    }

    {
        uint32_t entrySectors;
        uint32_t verifiedSectors;
        BOOL preparedAfterHandshake = FALSE;

        printf("Opening drive %c: for state-aware Xbox handshake...\n", driveLetter);
        if (!EnsureDriveReady(hDevice, 30000)) {
            printf("[XBOX-REF] Fatal: drive did not become ready before Xbox state preparation.\n");
            goto cleanup;
        }

        entrySectors = GetTotalSectors(hDevice);
        printf("[XBOX-REF] Entry READ CAPACITY: %u sectors.\n", entrySectors);

        if (xbox_ref_capacity_is_game_view(entrySectors)) {
            printf("[XBOX-REF] Entry state already exposes the Xbox game view; skipping the redundant initial handshake and tray cycle.\n");
        } else {
            printf("[XBOX-REF] Entry state appears locked/video; attempting the full handshake directly without a media transition.\n");
            UnlockDrive(hDevice);
            verifiedSectors = xbox_ref_refresh_ready_capacity(hDevice);
            preparedAfterHandshake = TRUE;
            printf("[XBOX-REF] Direct-handshake READ CAPACITY: %u sectors.\n", verifiedSectors);

            if (!xbox_ref_capacity_is_game_view(verifiedSectors)) {
                printf("[XBOX-REF][WARN] Direct handshake did not expose the Xbox game view; performing one tray-cycle recovery and retry.\n");
                AutomateTrayCycle(hDevice);
                printf("[XBOX-REF] Re-applying the full handshake after recovery media change.\n");
                UnlockDrive(hDevice);
                verifiedSectors = xbox_ref_refresh_ready_capacity(hDevice);
                printf("[XBOX-REF] Recovery-handshake READ CAPACITY: %u sectors.\n", verifiedSectors);

                if (!xbox_ref_capacity_is_game_view(verifiedSectors)) {
                    printf("[XBOX-REF] Fatal: Xbox game view was not established after direct and recovery handshakes.\n");
                    goto cleanup;
                }
            }
        }

        if (!preparedAfterHandshake)
            xbox_ref_refresh_ready_capacity(hDevice);
    }

    printf("Setting drive to maximum performance mode...\n");
    SetDriveSpeedMax(hDevice);

    if (!DeviceIoControl(hDevice, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) {
        printf("[!] Warning: Could not lock volume. Close any open folders pointing to the drive.\n");
        printf("[XBOX-REF] The reference dumper treats this as fatal before XBE/title probing.\n");
        goto cleanup;
    }
    volumeLocked = TRUE;

    printf("Searching for Xbox Game Signature (Raw SCSI Scan)...\n");
    game = GetXboxGameInfo(hDevice);
    printf("Game Title Raw: %s\n", game.TitleName);
    ReadXboxGameDir(hDevice);

    totalSectors = GetXboxPhysicalSectors(hDevice);
    isDualLayerBool = false;
    GetDiscMetadata(hDevice, &totalSectors, &isDualLayerBool, &game);
    isDualLayer = isDualLayerBool ? TRUE : FALSE;
    GetMediaID(hDevice, mediaId);

    if (result) {
        if (game.Success && game.TitleName[0]) {
            strncpy(result->title, game.TitleName, sizeof(result->title) - 1);
            result->title[sizeof(result->title) - 1] = '\0';
        }
        if (mediaId[0]) {
            strncpy(result->media_id, mediaId, sizeof(result->media_id) - 1);
            result->media_id[sizeof(result->media_id) - 1] = '\0';
        }
    }

    if (game.Success) {
        char titleCopy[sizeof(game.TitleName)];
        memset(titleCopy, 0, sizeof(titleCopy));
        strncpy(titleCopy, game.TitleName, sizeof(titleCopy) - 1);
        SanitizeFilename(titleCopy);
        if (filenameOverride) {
            strncpy(finalFilename, filename, sizeof(finalFilename) - 1);
            finalFilename[sizeof(finalFilename) - 1] = '\0';
            printf("[XBOX-REF] Output filename override: %s\n", finalFilename);
        } else {
            snprintf(finalFilename, sizeof(finalFilename), "%s[%s].%s",
                     titleCopy[0] ? titleCopy : "XboxDisc",
                     mediaId[0] ? mediaId : "UNKNOWN_ID",
                     (mode == '1') ? "iso" : "xiso");
            printf("[XBOX-REF] XBE/DMI-derived output filename: %s\n", finalFilename);
            xbox_ref_log_retarget(finalFilename);
        }
        DisplayXboxGameInfo(game);
        printf("\n--- DISC INFORMATION ---\n");
        printf("Physical Sectors: %u\n", totalSectors);
        printf("Layers:           %d\n", isDualLayer ? 2 : 1);
        printf("Media ID:         %s\n", mediaId);
        printf("Target File:      %s\n", finalFilename);
        printf("-------------------------------\n\n");
    } else {
        if (filenameOverride) {
            strncpy(finalFilename, filename, sizeof(finalFilename) - 1);
            finalFilename[sizeof(finalFilename) - 1] = '\0';
            printf("Error: Could not retrieve Xbox game information; using override filename %s.\n", finalFilename);
        } else {
            printf("Error: Could not retrieve Xbox game information and no output filename override was supplied.\n");
            printf("       Rerun with -i <file> or -X <file> if metadata probing cannot complete.\n");
            goto cleanup;
        }
    }

    if (result && finalFilename[0]) {
        strncpy(result->output_path, finalFilename, sizeof(result->output_path) - 1);
        result->output_path[sizeof(result->output_path) - 1] = '\0';
    }

    if (totalSectors != (uint32_t)(REDUMP_SECTORS)) {
        printf("[WARNING] Unlocked drive-reported sectors: %u does not match expected Xbox game-view sectors: %u\n", totalSectors, (uint32_t)(REDUMP_SECTORS));
        printf("-Homebrew games may have different sizes.\n\n");
    }

    if (totalSectors == 0) {
        printf("Error: Could not determine total sectors for dumping.\n");
        goto cleanup;
    }

    printf("Starting dump with copied DumpXboxGameDisc() mode %c...\n", mode);
    ok = DumpXboxGameDisc(hDevice, finalFilename, mode, totalSectors, isDualLayerBool, FALSE, result);

cleanup:
    if (volumeLocked)
        DeviceIoControl(hDevice, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
    if (ownsHandle && hDevice != INVALID_HANDLE_VALUE && hDevice != NULL) {
        printf("Issuing STOP UNIT / spin-down after dump attempt... ");
        if (StopDriveUnit(hDevice)) printf("OK\n"); else printf("FAILED\n");
        CloseDrive(hDevice);
    } else {
        printf("[XBOX-REF] Returning to FriiDump; final STOP UNIT cleanup will use the same handle.\n");
    }
    if (ownsHandle) {
        printf("[XBOX-REF] Log file complete: %s\n", xbox_ref_log_path() ? xbox_ref_log_path() : "(unavailable)");
        xbox_ref_log_close();
    } else if (ok) {
        printf("[XBOX-REF] Returning finalized output evidence to FriiDump's shared Redump verifier.\n");
    } else {
        printf("[XBOX-REF] No completed output evidence is available for shared Redump verification.\n");
    }
    return ok ? 0 : 1;
}

int xbox_ref_xgd1_layout_probe_with_handle(void *native_handle,
                                                const char *device,
                                                const char *report_path)
{
    return xbox_ref_xgd1_layout_probe_core((HANDLE)native_handle,
                                            device,
                                            report_path,
                                            FALSE);
}

int xbox_ref_xgd1_layout_probe(const char *device,
                               const char *report_path)
{
    char drive_letter;
    HANDLE hDevice;

    drive_letter = xbox_ref_drive_letter_from_device(device);
    if (!drive_letter)
    {
        xbox_ref_log_open_for_target(report_path, 0);
        printf("[XGD1-PROBE] Fatal: could not parse drive letter from device '%s'.\n",
               device ? device : "(null)");
        xbox_ref_log_close();
        return 1;
    }

    hDevice = OpenDrive(drive_letter);
    if (hDevice == INVALID_HANDLE_VALUE)
    {
        xbox_ref_log_open_for_target(report_path, drive_letter);
        printf("[XGD1-PROBE] Fatal: cannot open drive %c:. Run as Administrator.\n",
               drive_letter);
        xbox_ref_log_close();
        return 1;
    }

    return xbox_ref_xgd1_layout_probe_core(hDevice,
                                            device,
                                            report_path,
                                            TRUE);
}

int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
{
    return xbox_ref_gdr8050l_dump_core((HANDLE)native_handle, device, filename, mode, FALSE, result);
}

int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
{
    char driveLetter;
    HANDLE hDevice;

    driveLetter = xbox_ref_drive_letter_from_device(device);
    if (!driveLetter) {
        xbox_ref_log_open_for_target(filename, 0);
        printf("[XBOX-REF] Fatal: could not parse drive letter from device '%s'.\n", device ? device : "(null)");
        xbox_ref_log_close();
        return 1;
    }

    hDevice = OpenDrive(driveLetter);
    if (hDevice == INVALID_HANDLE_VALUE) {
        xbox_ref_log_open_for_target(filename, driveLetter);
        printf("[XBOX-REF] Fatal: Cannot open drive %c:. Run as Administrator.\n", driveLetter);
        xbox_ref_log_close();
        return 1;
    }

    return xbox_ref_gdr8050l_dump_core(hDevice, device, filename, mode, TRUE, result);
}
#else
int xbox_ref_xgd1_layout_probe_with_handle(void *native_handle,
                                                const char *device,
                                                const char *report_path)
{
    (void)native_handle;
    (void)device;
    (void)report_path;
    return 1;
}

int xbox_ref_xgd1_layout_probe(const char *device,
                               const char *report_path)
{
    (void)device;
    (void)report_path;
    return 1;
}

int xbox_ref_gdr8050l_dump_with_handle(void *native_handle, const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
{
    (void)native_handle; (void)device; (void)filename; (void)mode; xbox_ref_dump_result_init(result); return 1;
}

int xbox_ref_gdr8050l_dump(const char *device, const char *filename, char mode, xbox_ref_dump_result *result)
{
    (void)device; (void)filename; (void)mode; xbox_ref_dump_result_init(result); return 1;
}
#endif
