using System;
using System.Runtime.InteropServices;
using Decal.Interop.Dat;

namespace Decal.DecalDat
{
    [ComVisible(true)]
    [Guid("9F7F6CD9-D164-418D-8CB5-3B9ACD70BEAF")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("DecalDat.DatStream")]
    public class DatStreamImpl : IDatStream
    {
        private DatFileEntry _file;

        internal void Load(DatFileEntry file)
        {
            _file = file;
        }

        public int Size => _file?.Size ?? 0;

        public int Tell => _file?.Tell ?? 0;

        public void Skip(int Bytes)
        {
            _file?.Skip(Bytes);
        }

        public void Restart()
        {
            _file?.Reset();
        }

        public void ReadBinary(int Bytes, ref byte Buffer)
        {
            if (_file == null) return;

            var buf = new byte[Bytes];
            _file.Read(buf, 0, Bytes);

            // Pin the destination buffer for the duration of the copy
            unsafe
            {
                fixed (byte* p = &Buffer)
                {
                    Marshal.Copy(buf, 0, new IntPtr(p), Bytes);
                }
            }
        }

        public string Read(int Bytes)
        {
            if (_file == null) return string.Empty;

            var buf = new byte[Bytes];
            int read = _file.Read(buf, 0, Bytes);

            // Match C++ SysAllocStringByteLen: pack raw bytes into WCHAR pairs.
            // When the CLR marshals this string to BSTR, the raw bytes are preserved
            // byte-for-byte (each char = 2 raw bytes, little-endian).
            int charCount = (read + 1) / 2;
            var chars = new char[charCount];
            Buffer.BlockCopy(buf, 0, chars, 0, read);
            return new string(chars, 0, charCount);
        }
    }
}
