using System;
using NUnit.Framework;
using UnityEditor.Recorder.Timeline;
using UnityEngine;
using UnityEngine.Timeline;

namespace Streamingle.Editor.Tests
{
    public sealed class AICameraABRenderTests
    {
        [Test]
        public void ToInclusiveEndFrame_UsesEndExclusiveContract()
        {
            Assert.That(
                AICameraABRenderUtility.ToInclusiveEndFrame(10, 20, 100),
                Is.EqualTo(19));
        }

        [Test]
        public void ValidateFrameRange_RejectsEmptyRange()
        {
            Assert.Throws<ArgumentOutOfRangeException>(
                () => AICameraABRenderUtility.ValidateFrameRange(
                    10,
                    10,
                    100));
        }

        [Test]
        public void ValidateOutputSettings_RejectsOddMp4Dimensions()
        {
            Assert.Throws<ArgumentException>(
                () => AICameraABRenderUtility.ValidateOutputSettings(
                    AICameraABRenderCodec.MP4,
                    1919,
                    1080));
            Assert.DoesNotThrow(
                () => AICameraABRenderUtility.ValidateOutputSettings(
                    AICameraABRenderCodec.WEBM,
                    1919,
                    1080));
        }

        [Test]
        public void ValidateCandidatePair_RejectsDifferentTimeData()
        {
            var candidateA = CreateProbe("same-time");
            var candidateB = CreateProbe("different-time");
            var request = CreateRequest();

            Assert.Throws<System.IO.InvalidDataException>(
                () => AICameraABRenderUtility.ValidateCandidatePair(
                    candidateA,
                    candidateB,
                    request));
        }

        [Test]
        public void ValidateCandidatePair_RejectsDifferentDatasets()
        {
            var candidateA = CreateProbe("same-time", "dataset-a");
            var candidateB = CreateProbe("same-time", "dataset-b");

            Assert.Throws<System.IO.InvalidDataException>(
                () => AICameraABRenderUtility.ValidateCandidatePair(
                    candidateA,
                    candidateB,
                    CreateRequest()));
        }

        [Test]
        public void MuteCopiedRecorderTracks_MutesExistingRecorderTrack()
        {
            var timeline = ScriptableObject.CreateInstance<TimelineAsset>();
            try
            {
                var recorderTrack = timeline.CreateTrack<RecorderTrack>(
                    null,
                    "Existing Recorder");
                recorderTrack.muted = false;

                var mutedCount =
                    AICameraTimelinePreviewImporter.MuteCopiedRecorderTracks(
                        timeline);

                Assert.That(mutedCount, Is.EqualTo(1));
                Assert.That(recorderTrack.muted, Is.True);
                Assert.That(
                    AICameraTimelinePreviewImporter.MuteCopiedRecorderTracks(
                        timeline),
                    Is.Zero);
            }
            finally
            {
                UnityEngine.Object.DestroyImmediate(timeline);
            }
        }

        [Test]
        public void WriteJsonAtomic_ReplacesExistingStateWithoutTempFiles()
        {
            var directory = System.IO.Path.Combine(
                System.IO.Path.GetTempPath(),
                $"cw-ai-ab-json-{Guid.NewGuid():N}");
            var path = System.IO.Path.Combine(directory, "active_job.json");
            try
            {
                AICameraABRenderUtility.WriteJsonAtomic(
                    path,
                    new AICameraABRenderJobState { jobId = "first" });
                AICameraABRenderUtility.WriteJsonAtomic(
                    path,
                    new AICameraABRenderJobState { jobId = "second" });

                var restored =
                    AICameraABRenderUtility.ReadJson<AICameraABRenderJobState>(
                        path);
                Assert.That(restored.jobId, Is.EqualTo("second"));
                Assert.That(
                    System.IO.Directory.GetFiles(directory, "*.tmp"),
                    Is.Empty);
            }
            finally
            {
                if (System.IO.Directory.Exists(directory))
                {
                    System.IO.Directory.Delete(directory, true);
                }
            }
        }

        private static AICameraABCandidateProbe CreateProbe(
            string timeSha,
            string datasetId = "dataset")
        {
            return new AICameraABCandidateProbe
            {
                Metadata = new AICameraABGeneratedCameraMetadata(),
                Result = new AICameraABCandidateResult
                {
                    sampleRate = 60,
                    frameCount = 120,
                    duration = 2,
                    timeSha256 = timeSha,
                    songId = "song",
                    datasetId = datasetId,
                    targetEvaluationGroupId = "group",
                    targetAspectRatio = 16.0 / 9.0
                }
            };
        }

        private static AICameraABRenderRequest CreateRequest()
        {
            return new AICameraABRenderRequest
            {
                startFrame = 0,
                endFrameExclusive = 120,
                codec = AICameraABRenderCodec.MP4,
                width = 1920,
                height = 1080
            };
        }
    }
}
