using System.Collections.Generic;
using UnityEngine;

namespace ServiceSim
{
    /// <summary>
    /// 回す条件と、書き出す場所。実験に関する数字と場所はすべてこの .asset に置く。
    /// 条件を順に回すのは ExperimentRunner（段階2で作る）。
    /// </summary>
    [CreateAssetMenu(menuName = "ServiceSim/Experiment Plan", fileName = "ExperimentPlan")]
    public class ExperimentPlan : ScriptableObject
    {
        public struct Condition
        {
            public string id;
            public int aisleWidthIndex;
            public float aisleWidthM;
            public CrowdLevel crowd;
            public int robots;
        }

        [Header("この回の名前")]
        public string runName = "family_v0";

        [Header("回す条件")]
        [Tooltip("細い通路の幅（StoreLayout.aisleWidthOptions の番号）")]
        public int[] aisleWidthIndices = { 0, 1, 2 };

        [Tooltip("混み具合")]
        public CrowdLevel[] crowdLevels = { CrowdLevel.Empty, CrowdLevel.Normal, CrowdLevel.Busy };

        [Tooltip("ロボットの台数")]
        public int[] robotCounts = { 1, 2 };

        [Header("1条件で回す量")]
        [Tooltip("1条件・1つの種で回す往復の数。台数を合わせた合計")]
        public int tripsPerCondition = 100;

        [Tooltip("乱数の種")]
        public int[] seeds = { 0, 1, 2, 3, 4 };

        [Tooltip("時間の進みを速める倍率")]
        public float timeScale = 1f;

        [Header("書き出す場所")]
        [Tooltip("KIOXIA がつながっているかを確かめる場所")]
        public string kioxiaVolumePath = "/Volumes/KIOXIA";

        [Tooltip("測ったデータの置き場所。この下に {YYYYMMDD}_{run_name}/ を作る")]
        public string kioxiaOutputRoot = "/Volumes/KIOXIA/r2r2r-data/service_sim/unity";

        [Header("段階2：1条件だけ試す")]
        [Tooltip("細い通路の幅（StoreLayout.aisleWidthOptions の番号）")]
        public int trialAisleWidthIndex = 1;

        [Tooltip("混み具合")]
        public CrowdLevel trialCrowd = CrowdLevel.Normal;

        [Tooltip("ロボットの台数")]
        public int trialRobots = 2;

        [Tooltip("乱数の種")]
        public int trialSeed = 0;

        [Tooltip("回す往復の数（台数を合わせた合計）。timeScale 1 で20分程度に収まる数にする")]
        public int trialTrips = 20;

        [Tooltip("速めるときの倍率")]
        public float trialTimeScaleFast = 10f;

        [Tooltip("1コマの時間を固定して回すときの、1コマの長さ（秒）")]
        public float trialCaptureDeltaTime = 0.02f;

        [Tooltip("実時間でこれを超えたら打ち切る（秒）。保険")]
        public float trialMaxWallSeconds = 2400f;

        [Tooltip("段階2の置き場所。Plastic のワークスペースと git の外にする（測定データとして残さない）")]
        public string trialOutputRoot = "/Users/shimazueiichi/ServiceSim_tmp";

        [Header("v2：1回の実行の区切り")]
        [Tooltip("1回の実行の長さ（店の中の分）。試算の peak_min と同じ")]
        public float measureMinutes = 120f;

        [Tooltip("慣らしの長さ（店の中の分）。この分は計測に数えない")]
        public float warmupMinutes = 15f;

        [Header("v2：速く回す")]
        [Tooltip("段階3で使う1コマの長さ（秒）。0.05 で約24倍速")]
        public float measureCaptureDeltaTime = 0.05f;

        [Tooltip("確かめ用に使う1コマの長さ（秒）。検査1・2でこちらと比べる")]
        public float referenceCaptureDeltaTime = 0.02f;

        [Tooltip("回している間、カメラを切って描画を止める。計測を速くするため初期値は ON")]
        public bool disableRenderingWhileRunning = true;

        [Tooltip("回している間も頭の上の字幕を出す（B11 を一時的に外す）。" +
                 "人がロボットをよける様子を見て絵を撮るときだけ ON にする。計測は遅くなる")]
        public bool showLabelsWhileRunning;

        [Tooltip("キッチンの屋根のモニターを出す（2026-10-23）。" +
                 "板1枚と文字だけなので、測る回でも出す。倍速が落ちるなど問題があれば切る")]
        public bool showKitchenMonitor = true;

        [Header("v2：段階3（18条件 × 種）")]
        [Tooltip("段階3の置き場所。この下に {YYYYMMDD}_{run_name}/{condition}_s{seed}/ を作る")]
        public string stage3OutputRoot = "/Users/shimazueiichi/ServiceSim_tmp/stage3";

        [Tooltip("すでに書き出してある条件は飛ばす（途中から再開する）")]
        public bool stage3Resume = true;

        [Header("スクリーンショット")]
        [Tooltip("段階1の報告に使う画面の置き場所")]
        public string screenshotDir = "/Users/shimazueiichi/Library/Mobile Documents/com~apple~CloudDocs/デスクトップ/ADAPT DESIGN/じぶんの/PixelstoMotors/デジタルツイン学習R2R2R/サービスロボット導入シミュレーション/unity/screens";

        public int screenshotWidth = 1920;
        public int screenshotHeight = 1080;

        /// <summary>条件の数（通路の幅 × 混み具合 × 台数）</summary>
        public int ConditionCount
        {
            get
            {
                int w = aisleWidthIndices != null ? aisleWidthIndices.Length : 0;
                int c = crowdLevels != null ? crowdLevels.Length : 0;
                int r = robotCounts != null ? robotCounts.Length : 0;
                return w * c * r;
            }
        }

        /// <summary>18条件を順に並べる</summary>
        public List<Condition> BuildConditions(StoreLayout layout)
        {
            List<Condition> list = new List<Condition>();
            if (aisleWidthIndices == null || crowdLevels == null || robotCounts == null) return list;

            for (int wi = 0; wi < aisleWidthIndices.Length; wi++)
            {
                int widthIndex = aisleWidthIndices[wi];
                float widthM = 0f;
                if (layout != null && layout.aisleWidthOptions != null &&
                    widthIndex >= 0 && widthIndex < layout.aisleWidthOptions.Length)
                    widthM = layout.aisleWidthOptions[widthIndex];

                for (int ci = 0; ci < crowdLevels.Length; ci++)
                {
                    for (int ri = 0; ri < robotCounts.Length; ri++)
                    {
                        Condition c = new Condition();
                        c.aisleWidthIndex = widthIndex;
                        c.aisleWidthM = widthM;
                        c.crowd = crowdLevels[ci];
                        c.robots = robotCounts[ri];
                        c.id = ConditionId(widthM, c.crowd, c.robots);
                        list.Add(c);
                    }
                }
            }
            return list;
        }

        public static string ConditionId(float aisleWidthM, CrowdLevel crowd, int robots)
        {
            int mm = Mathf.RoundToInt(aisleWidthM * 100f);
            return "w" + mm.ToString("000") + "_" + CrowdName(crowd) + "_r" + robots.ToString();
        }

        public static string CrowdName(CrowdLevel crowd)
        {
            switch (crowd)
            {
                case CrowdLevel.Empty: return "empty";
                case CrowdLevel.Busy: return "busy";
                default: return "normal";
            }
        }
    }
}
