using NUnit.Framework;

namespace TIASshot.Tests {
    /// <summary>
    /// GainCalc.CalcRatio のテスト
    /// </summary>
    [TestFixture]
    public class GainCalcTests {

        // ---------------------------------------------------------------
        // 通常ケース
        // ---------------------------------------------------------------

        /// <summary>
        /// CalcRatio_通常ケースupdateRate0_5_正しい比率を返す:
        /// value=100, target=200, updateRate=0.5 → (200/100 - 1) * 0.5 + 1 = 1.5
        /// </summary>
        [Test]
        public void CalcRatio_通常ケースupdateRate0_5_正しい比率を返す() {
            float result = GainCalc.CalcRatio(100.0f, 200.0f, 0.5f);
            Assert.AreEqual(1.5f, result, 1e-6f);
        }

        // ---------------------------------------------------------------
        // updateRate が変わると比率が変わること
        // ---------------------------------------------------------------

        /// <summary>
        /// CalcRatio_updateRate1_0_係数1倍の比率を返す:
        /// value=100, target=200, updateRate=1.0 → (200/100 - 1) * 1.0 + 1 = 2.0
        /// </summary>
        [Test]
        public void CalcRatio_updateRate1_0_係数1倍の比率を返す() {
            float result = GainCalc.CalcRatio(100.0f, 200.0f, 1.0f);
            Assert.AreEqual(2.0f, result, 1e-6f);
        }

        /// <summary>
        /// CalcRatio_updateRate0_1_updateRateが小さいほど変化量が小さい:
        /// value=100, target=200, updateRate=0.1 → (200/100 - 1) * 0.1 + 1 = 1.1
        /// </summary>
        [Test]
        public void CalcRatio_updateRate0_1_updateRateが小さいほど変化量が小さい() {
            float result = GainCalc.CalcRatio(100.0f, 200.0f, 0.1f);
            Assert.AreEqual(1.1f, result, 1e-6f);
        }

        // ---------------------------------------------------------------
        // value == target のとき比率は 1.0
        // ---------------------------------------------------------------

        /// <summary>
        /// CalcRatio_valueがtargetと等しい_updateRateによらず比率は1:
        /// value == target のとき ratio = target/value = 1、(1 - 1) * anything + 1 = 1
        /// </summary>
        [Test]
        public void CalcRatio_valueがtargetと等しい_updateRate0_5_比率は1() {
            float result = GainCalc.CalcRatio(150.0f, 150.0f, 0.5f);
            Assert.AreEqual(1.0f, result, 1e-6f);
        }

        /// <summary>
        /// CalcRatio_valueがtargetと等しい_updateRateを変えても結果が同じ:
        /// value == target のとき updateRate=0.5 と updateRate=1.0 の結果が一致する
        /// （updateRate に依存しないことを比較で検証する）
        /// </summary>
        [Test]
        public void CalcRatio_valueがtargetと等しい_updateRateを変えても結果が同じ() {
            float result05 = GainCalc.CalcRatio(150.0f, 150.0f, 0.5f);
            float result10 = GainCalc.CalcRatio(150.0f, 150.0f, 1.0f);
            Assert.AreEqual(result05, result10, 1e-6f, "value==target のとき updateRate によらず結果が同じ");
        }

        // ---------------------------------------------------------------
        // value == 255.0f の特別扱い
        // ---------------------------------------------------------------

        /// <summary>
        /// CalcRatio_value255_updateRate0_5_係数は常に1_0になる:
        /// value=255 のとき updateRate を無視して係数 1.0 を使う
        /// → (200/255 - 1) * 1.0 + 1 = 200/255
        /// </summary>
        [Test]
        public void CalcRatio_value255_updateRate0_5_係数は常に1_0になる() {
            float expected = 200.0f / 255.0f;
            float result = GainCalc.CalcRatio(255.0f, 200.0f, 0.5f);
            Assert.AreEqual(expected, result, 1e-6f);
        }

        /// <summary>
        /// CalcRatio_value255_updateRateを変えても結果が同じ:
        /// value=255 では updateRate=0.5 と updateRate=1.0 の結果が一致する
        /// </summary>
        [Test]
        public void CalcRatio_value255_updateRateを変えても結果が同じ() {
            float result05 = GainCalc.CalcRatio(255.0f, 200.0f, 0.5f);
            float result10 = GainCalc.CalcRatio(255.0f, 200.0f, 1.0f);
            Assert.AreEqual(result05, result10, 1e-6f, "value==255 のとき updateRate によらず結果が同じ");
        }

        // ---------------------------------------------------------------
        // ゲイン減少方向（target < value）
        // ---------------------------------------------------------------

        /// <summary>
        /// CalcRatio_targetがvalueより小さい_比率が1未満になる:
        /// value=200, target=100, updateRate=0.5 → (100/200 - 1) * 0.5 + 1 = 0.75
        /// ゲインが目標より高すぎる場合に比率が 1.0 未満（下降補正）になることを確認する
        /// </summary>
        [Test]
        public void CalcRatio_targetがvalueより小さい_updateRate0_5_比率が1未満になる() {
            float result = GainCalc.CalcRatio(200.0f, 100.0f, 0.5f);
            Assert.AreEqual(0.75f, result, 1e-6f);
        }

        // ---------------------------------------------------------------
        // updateRate=0 のとき比率は常に 1.0
        // ---------------------------------------------------------------

        /// <summary>
        /// CalcRatio_updateRate0_比率は常に1:
        /// value != target でも updateRate=0 なら (ratio-1)*0+1 = 1.0
        /// 更新が停止する境界値として確認する
        /// </summary>
        [Test]
        public void CalcRatio_updateRate0_比率は常に1() {
            float result = GainCalc.CalcRatio(100.0f, 200.0f, 0.0f);
            Assert.AreEqual(1.0f, result, 1e-6f);
        }

        // ---------------------------------------------------------------
        // ゼロ除算の挙動（現状記録）
        // ---------------------------------------------------------------

        /// <summary>
        /// CalcRatio_value0_戻り値はInfinityまたはNaN_例外は出ない:
        /// float では 0 除算は例外にならず Infinity / NaN になる（現状挙動の固定）
        /// </summary>
        [Test]
        public void CalcRatio_value0_戻り値はInfinityまたはNaN_例外は出ない() {
            float result = GainCalc.CalcRatio(0.0f, 200.0f, 0.5f);
            // float(0 除算) は例外を投げずに Infinity / NaN を返す
            Assert.IsTrue(float.IsInfinity(result) || float.IsNaN(result),
                "value=0 のとき戻り値は Infinity または NaN になる（例外は出ない）");
        }
    }
}
