#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
#include <libavutil/pixdesc.h>
#include <libavutil/intreadwrite.h>
#include <libavutil/mem.h>
#include <libavutil/avassert.h>
#include <libswscale/swscale.h>
#include "libavcodec/bytestream.h"

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    if (size < 128)
        return 0;

    // Initialize input reader
    GetByteContext gbc;
    bytestream2_init(&gbc, data, size);

    // Read parameters from input
    int srcW = bytestream2_get_le32(&gbc);
    int srcH = bytestream2_get_le16(&gbc);
    int dstW = bytestream2_get_le32(&gbc);
    int dstH = bytestream2_get_le16(&gbc);
    int flags = bytestream2_get_le32(&gbc);
    int srcFormat = bytestream2_get_le32(&gbc);
    int dstFormat = bytestream2_get_le32(&gbc);
    int64_t flags64 = bytestream2_get_le64(&gbc);

    // New: fuzzed srcSliceY, ensure within valid range
    int fuzz_srcSliceY = bytestream2_get_le32(&gbc);
    if (srcH <= 0 || dstH <= 0 || srcW <= 0 || dstW <= 0)
        return 0;

    fuzz_srcSliceY %= srcH;

    const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(srcFormat);
    const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(dstFormat);
    if (!desc_src || !desc_dst)
        return 0;

    // Allocate SwsContext
    struct SwsContext *sws = sws_getContext(
        srcW, srcH, srcFormat,
        dstW, dstH, dstFormat,
        flags, NULL, NULL, NULL
    );
    if (!sws)
        return 0;

    if (sws_init_context(sws, NULL, NULL) < 0)
        goto end;

    // Allocate image buffers
    uint8_t *src_data[4] = {0};
    int src_linesize[4];
    uint8_t *dst_data[4] = {0};
    int dst_linesize[4];

    if (av_image_alloc(src_data, src_linesize, srcW, srcH, srcFormat, 1) < 0)
        goto end;
    if (av_image_alloc(dst_data, dst_linesize, dstW, dstH, dstFormat, 1) < 0)
        goto cleanup_src;

    // Copy remaining input data into source buffer
    size_t remaining = size - bytestream2_tell(&gbc);
    if (remaining > 0) {
        size_t copy_size = FFMIN(remaining, av_image_get_buffer_size(srcFormat, srcW, srcH, 1));
        memcpy(src_data[0], data + bytestream2_tell(&gbc), copy_size);
    }

    // Call sws_scale with fuzzed srcSliceY
    sws_scale(sws,
              (const uint8_t * const*)src_data, src_linesize,
              fuzz_srcSliceY, srcH,
              dst_data, dst_linesize);

    av_freep(&dst_data[0]);
cleanup_src:
    av_freep(&src_data[0]);
end:
    sws_freeContext(sws);
    return 0;
}
