using UnityEngine;
using UnityEditor;
using TMPro;
using Unity.Cinemachine;

public class ArcadeSceneSetup : EditorWindow
{
    private GameObject playerPrefab;
    private RuntimeAnimatorController animatorController;

    [MenuItem("AL-Arcade/Setup Scene %#m")]
    public static void ShowWindow()
    {
        GetWindow<ArcadeSceneSetup>("AL-Arcade Scene Setup");
    }

    [MenuItem("AL-Arcade/Quick Setup (Full Scene) %#b")]
    public static void QuickSetup()
    {
        var window = GetWindow<ArcadeSceneSetup>("AL-Arcade Scene Setup");
        window.BuildFullScene();
    }

    private void OnGUI()
    {
        GUILayout.Label("AL-Arcade Scene Scaffolding", EditorStyles.boldLabel);
        EditorGUILayout.Space(10);

        EditorGUILayout.HelpBox(
            "This tool sets up the full multiplayer scene:\n" +
            "- NetworkManager (auto-connects)\n" +
            "- Local Player prefab (WASD + name tag)\n" +
            "- Remote Player prefab (interpolated + name tag)\n" +
            "- Cinemachine camera (close follow)\n" +
            "- UI Canvas (name changer + joystick)\n" +
            "- Ground plane + lighting",
            MessageType.Info);

        EditorGUILayout.Space(10);

        playerPrefab = (GameObject)EditorGUILayout.ObjectField(
            "Player Prefab", playerPrefab, typeof(GameObject), false);

        animatorController = (RuntimeAnimatorController)EditorGUILayout.ObjectField(
            "Animator Controller", animatorController, typeof(RuntimeAnimatorController), false);

        EditorGUILayout.Space(5);

        if (playerPrefab == null)
        {
            EditorGUILayout.HelpBox(
                "Drag your character prefab here (must have Animator).\nIf empty, a capsule placeholder will be used.",
                MessageType.None);
        }

        EditorGUILayout.Space(15);

        if (GUILayout.Button("Build Full Scene", GUILayout.Height(40)))
        {
            BuildFullScene();
        }

        EditorGUILayout.Space(5);

        if (GUILayout.Button("Create Local Player Prefab Only"))
        {
            CreateLocalPlayerPrefab();
        }

        if (GUILayout.Button("Create Remote Player Prefab Only"))
        {
            CreateRemotePlayerPrefab();
        }

        EditorGUILayout.Space(10);

        if (GUILayout.Button("Setup Cinemachine Camera"))
        {
            SetupCamera();
        }

        if (GUILayout.Button("Setup UI Canvas"))
        {
            SetupUI();
        }
    }

    private void BuildFullScene()
    {
        Undo.SetCurrentGroupName("AL-Arcade Scene Setup");

        SetupNetworkManager();
        var localPrefab = CreateLocalPlayerPrefab();
        var remotePrefab = CreateRemotePlayerPrefab();
        SetupCamera();
        SetupUI();
        SetupEnvironment();

        var nm = FindFirstObjectByType<ArcadeNetworkManager>();
        if (nm != null)
        {
            var so = new SerializedObject(nm);
            so.FindProperty("localPlayerPrefab").objectReferenceValue = localPrefab;
            so.FindProperty("remotePlayerPrefab").objectReferenceValue = remotePrefab;
            so.ApplyModifiedProperties();
        }

        Debug.Log("[AL-Arcade] Scene setup complete! Press Play to test.");
    }

    private void SetupNetworkManager()
    {
        if (FindFirstObjectByType<ArcadeNetworkManager>() != null) return;

        var go = new GameObject("--- NETWORK MANAGER ---");
        Undo.RegisterCreatedObjectUndo(go, "Create NetworkManager");
        go.AddComponent<ArcadeNetworkManager>();
    }

    private GameObject CreateLocalPlayerPrefab()
    {
        string path = "Assets/_Project/Prefabs";
        EnsureFolder(path);

        var root = new GameObject("LocalPlayer");

        // Character visual
        GameObject visual;
        if (playerPrefab != null)
        {
            visual = (GameObject)PrefabUtility.InstantiatePrefab(playerPrefab);
            visual.transform.SetParent(root.transform);
            visual.transform.localPosition = Vector3.zero;
            visual.transform.localRotation = Quaternion.identity;
        }
        else
        {
            visual = CreatePlaceholderCharacter(root.transform, new Color(0.3f, 0.6f, 1f));
        }

        // Animator
        var animator = root.GetComponentInChildren<Animator>();
        if (animator == null)
            animator = visual.AddComponent<Animator>();
        if (animatorController != null)
            animator.runtimeAnimatorController = animatorController;

        // Scripts
        root.AddComponent<LocalPlayerController>();
        root.AddComponent<PlayerInteract>();

        // Collider
        var col = root.AddComponent<CapsuleCollider>();
        col.center = new Vector3(0, 1f, 0);
        col.radius = 0.4f;
        col.height = 2f;

        // Rigidbody (kinematic)
        var rb = root.AddComponent<Rigidbody>();
        rb.isKinematic = true;

        // Name tag
        CreateNameTag(root.transform);


        // Save prefab
        string prefabPath = path + "/LocalPlayer.prefab";
        var prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(
            root, prefabPath, InteractionMode.UserAction);

        DestroyImmediate(root);
        Debug.Log($"[AL-Arcade] Local player prefab saved: {prefabPath}");
        return prefab;
    }

    private GameObject CreateRemotePlayerPrefab()
    {
        string path = "Assets/_Project/Prefabs";
        EnsureFolder(path);

        var root = new GameObject("RemotePlayer");

        // Character visual
        GameObject visual;
        if (playerPrefab != null)
        {
            visual = (GameObject)PrefabUtility.InstantiatePrefab(playerPrefab);
            visual.transform.SetParent(root.transform);
            visual.transform.localPosition = Vector3.zero;
            visual.transform.localRotation = Quaternion.identity;
        }
        else
        {
            visual = CreatePlaceholderCharacter(root.transform, new Color(1f, 0.5f, 0.3f));
        }

        // Animator
        var animator = root.GetComponentInChildren<Animator>();
        if (animator == null)
            animator = visual.AddComponent<Animator>();
        if (animatorController != null)
            animator.runtimeAnimatorController = animatorController;

        // Remote controller
        root.AddComponent<RemotePlayerController>();

        // Name tag
        CreateNameTag(root.transform);

        // Save prefab
        string prefabPath = path + "/RemotePlayer.prefab";
        var prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(
            root, prefabPath, InteractionMode.UserAction);

        DestroyImmediate(root);
        Debug.Log($"[AL-Arcade] Remote player prefab saved: {prefabPath}");
        return prefab;
    }

    private void SetupCamera()
    {
        // Main Camera
        var mainCam = Camera.main;
        if (mainCam == null)
        {
            var camGo = new GameObject("Main Camera");
            Undo.RegisterCreatedObjectUndo(camGo, "Create Camera");
            mainCam = camGo.AddComponent<Camera>();
            camGo.AddComponent<AudioListener>();
            camGo.tag = "MainCamera";
        }

        mainCam.transform.position = new Vector3(0, 8f, -5f);
        mainCam.transform.rotation = Quaternion.Euler(50f, 0f, 0f);
        mainCam.fieldOfView = 40f;
        mainCam.orthographic = false;

        // Cinemachine Brain on main camera
        var brain = mainCam.GetComponent<CinemachineBrain>();
        if (brain == null)
            brain = mainCam.gameObject.AddComponent<CinemachineBrain>();

        // Cinemachine Camera (virtual)
        var existingVcam = FindFirstObjectByType<CinemachineCamera>();
        GameObject vcamGo;
        CinemachineCamera vcam;

        if (existingVcam != null)
        {
            vcam = existingVcam;
            vcamGo = vcam.gameObject;
        }
        else
        {
            vcamGo = new GameObject("CM PlayerFollow");
            Undo.RegisterCreatedObjectUndo(vcamGo, "Create Cinemachine Camera");
            vcam = vcamGo.AddComponent<CinemachineCamera>();
        }

        // Position offset body — use CinemachineFollow (Cinemachine 3.x)
        var follow = vcamGo.GetComponent<CinemachineFollow>();
        if (follow == null)
            follow = vcamGo.AddComponent<CinemachineFollow>();

        follow.FollowOffset = new Vector3(0f, 8f, -5f);
        follow.TrackerSettings.PositionDamping = new Vector3(0.5f, 0.5f, 0.5f);

        // Rotation composer — use CinemachineRotationComposer
        var composer = vcamGo.GetComponent<CinemachineRotationComposer>();
        if (composer == null)
            composer = vcamGo.AddComponent<CinemachineRotationComposer>();

        // Camera follow script to auto-wire the target at runtime
        var camFollow = vcamGo.GetComponent<CameraFollowPlayer>();
        if (camFollow == null)
            camFollow = vcamGo.AddComponent<CameraFollowPlayer>();

        Debug.Log("[AL-Arcade] Cinemachine camera set up (close follow, damped)");
    }

    private void SetupUI()
    {
        if (FindFirstObjectByType<PlayerNameChanger>() != null) return;

        var canvasGo = new GameObject("--- UI CANVAS ---");
        Undo.RegisterCreatedObjectUndo(canvasGo, "Create UI Canvas");

        var canvas = canvasGo.AddComponent<Canvas>();
        canvas.renderMode = RenderMode.ScreenSpaceOverlay;
        canvas.sortingOrder = 100;
        canvasGo.AddComponent<UnityEngine.UI.CanvasScaler>().uiScaleMode =
            UnityEngine.UI.CanvasScaler.ScaleMode.ScaleWithScreenSize;
        canvasGo.AddComponent<UnityEngine.UI.GraphicRaycaster>();

        // Name change panel
        var panel = CreateUIPanel(canvasGo.transform);
        var nameChanger = canvasGo.AddComponent<PlayerNameChanger>();

        var so = new SerializedObject(nameChanger);
        so.FindProperty("namePanel").objectReferenceValue = panel.gameObject;
        var inputField = panel.GetComponentInChildren<TMP_InputField>();
        if (inputField != null)
            so.FindProperty("nameInput").objectReferenceValue = inputField;
        var button = panel.GetComponentInChildren<UnityEngine.UI.Button>();
        if (button != null)
            so.FindProperty("confirmButton").objectReferenceValue = button;
        so.ApplyModifiedProperties();

        // Online count display
        var countGo = new GameObject("OnlineCount");
        countGo.transform.SetParent(canvasGo.transform, false);
        var countRect = countGo.AddComponent<RectTransform>();
        countRect.anchorMin = new Vector2(1, 1);
        countRect.anchorMax = new Vector2(1, 1);
        countRect.pivot = new Vector2(1, 1);
        countRect.anchoredPosition = new Vector2(-15, -15);
        countRect.sizeDelta = new Vector2(200, 30);
        var countText = countGo.AddComponent<TextMeshProUGUI>();
        countText.text = "Online: --";
        countText.fontSize = 14;
        countText.alignment = TextAlignmentOptions.TopRight;
        countText.color = new Color(1, 1, 1, 0.7f);

        // Hint text
        var hintGo = new GameObject("HintText");
        hintGo.transform.SetParent(canvasGo.transform, false);
        var hintRect = hintGo.AddComponent<RectTransform>();
        hintRect.anchorMin = new Vector2(0.5f, 0);
        hintRect.anchorMax = new Vector2(0.5f, 0);
        hintRect.pivot = new Vector2(0.5f, 0);
        hintRect.anchoredPosition = new Vector2(0, 15);
        hintRect.sizeDelta = new Vector2(300, 25);
        var hintText = hintGo.AddComponent<TextMeshProUGUI>();
        hintText.text = "TAB to change name · WASD to move · E to interact";
        hintText.fontSize = 11;
        hintText.alignment = TextAlignmentOptions.Center;
        hintText.color = new Color(1, 1, 1, 0.4f);

        Debug.Log("[AL-Arcade] UI Canvas created (name changer + hints)");
    }

    private void SetupEnvironment()
    {
        if (GameObject.Find("Ground") == null)
        {
            var ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
            ground.name = "Ground";
            ground.transform.position = Vector3.zero;
            ground.transform.localScale = new Vector3(5, 1, 5);
            Undo.RegisterCreatedObjectUndo(ground, "Create Ground");

            var mat = new Material(Shader.Find("Universal Render Pipeline/Lit"));
            mat.color = new Color(0.15f, 0.15f, 0.2f);
            ground.GetComponent<Renderer>().sharedMaterial = mat;
        }

        var light = FindFirstObjectByType<Light>();
        if (light == null)
        {
            var lightGo = new GameObject("Directional Light");
            Undo.RegisterCreatedObjectUndo(lightGo, "Create Light");
            light = lightGo.AddComponent<Light>();
            light.type = LightType.Directional;
        }
        light.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
        light.intensity = 1.2f;
        light.color = new Color(1f, 0.95f, 0.9f);
    }

    // --- Helpers ---

    private GameObject CreatePlaceholderCharacter(Transform parent, Color color)
    {
        var visual = new GameObject("Visual");
        visual.transform.SetParent(parent);
        visual.transform.localPosition = Vector3.zero;

        var body = GameObject.CreatePrimitive(PrimitiveType.Capsule);
        body.name = "Body";
        body.transform.SetParent(visual.transform);
        body.transform.localPosition = new Vector3(0, 1f, 0);
        body.transform.localScale = new Vector3(0.6f, 0.8f, 0.6f);
        DestroyImmediate(body.GetComponent<Collider>());

        var mat = new Material(Shader.Find("Universal Render Pipeline/Lit"));
        mat.color = color;
        body.GetComponent<Renderer>().sharedMaterial = mat;

        var head = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        head.name = "Head";
        head.transform.SetParent(visual.transform);
        head.transform.localPosition = new Vector3(0, 1.9f, 0);
        head.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f);
        DestroyImmediate(head.GetComponent<Collider>());
        head.GetComponent<Renderer>().sharedMaterial = mat;

        return visual;
    }

    private void CreateNameTag(Transform parent)
    {
        var tagGo = new GameObject("NameTag");
        tagGo.transform.SetParent(parent);
        tagGo.transform.localPosition = new Vector3(0, 2.4f, 0);

        var nameTag = tagGo.AddComponent<PlayerNameTag>();

        var textGo = new GameObject("NameText");
        textGo.transform.SetParent(tagGo.transform);
        textGo.transform.localPosition = Vector3.zero;

        var tmp = textGo.AddComponent<TextMeshPro>();
        tmp.text = "Visitor";
        tmp.fontSize = 3f;
        tmp.alignment = TextAlignmentOptions.Center;
        tmp.color = Color.white;
        tmp.fontSharedMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, 0.2f);
        tmp.fontSharedMaterial.SetColor(ShaderUtilities.ID_OutlineColor, Color.black);
        tmp.enableWordWrapping = false;
        tmp.overflowMode = TextOverflowModes.Overflow;

        var rect = textGo.GetComponent<RectTransform>();
        rect.sizeDelta = new Vector2(4f, 1f);

        var so = new SerializedObject(nameTag);
        so.FindProperty("nameText").objectReferenceValue = tmp;
        so.ApplyModifiedProperties();
    }


    private GameObject CreateUIPanel(Transform parent)
    {
        var panel = new GameObject("NameChangePanel");
        panel.transform.SetParent(parent, false);
        var panelRect = panel.AddComponent<RectTransform>();
        panelRect.anchorMin = new Vector2(0.5f, 0.5f);
        panelRect.anchorMax = new Vector2(0.5f, 0.5f);
        panelRect.sizeDelta = new Vector2(300, 60);
        panelRect.anchoredPosition = new Vector2(0, -100);

        var bg = panel.AddComponent<UnityEngine.UI.Image>();
        bg.color = new Color(0.1f, 0.1f, 0.15f, 0.9f);

        // Input field
        var inputGo = new GameObject("NameInput");
        inputGo.transform.SetParent(panel.transform, false);
        var inputRect = inputGo.AddComponent<RectTransform>();
        inputRect.anchorMin = new Vector2(0, 0);
        inputRect.anchorMax = new Vector2(0.7f, 1);
        inputRect.offsetMin = new Vector2(10, 10);
        inputRect.offsetMax = new Vector2(-5, -10);

        var inputImage = inputGo.AddComponent<UnityEngine.UI.Image>();
        inputImage.color = new Color(0.2f, 0.2f, 0.25f, 1f);

        var inputField = inputGo.AddComponent<TMP_InputField>();
        inputField.characterLimit = 16;

        var inputTextGo = new GameObject("Text");
        inputTextGo.transform.SetParent(inputGo.transform, false);
        var inputTextRect = inputTextGo.AddComponent<RectTransform>();
        inputTextRect.anchorMin = Vector2.zero;
        inputTextRect.anchorMax = Vector2.one;
        inputTextRect.offsetMin = new Vector2(8, 0);
        inputTextRect.offsetMax = new Vector2(-8, 0);
        var inputText = inputTextGo.AddComponent<TextMeshProUGUI>();
        inputText.fontSize = 16;
        inputText.color = Color.white;
        inputField.textComponent = inputText;

        var placeholderGo = new GameObject("Placeholder");
        placeholderGo.transform.SetParent(inputGo.transform, false);
        var phRect = placeholderGo.AddComponent<RectTransform>();
        phRect.anchorMin = Vector2.zero;
        phRect.anchorMax = Vector2.one;
        phRect.offsetMin = new Vector2(8, 0);
        phRect.offsetMax = new Vector2(-8, 0);
        var phText = placeholderGo.AddComponent<TextMeshProUGUI>();
        phText.text = "Enter name...";
        phText.fontSize = 16;
        phText.color = new Color(1, 1, 1, 0.3f);
        phText.fontStyle = FontStyles.Italic;
        inputField.placeholder = phText;

        // Confirm button
        var btnGo = new GameObject("ConfirmBtn");
        btnGo.transform.SetParent(panel.transform, false);
        var btnRect = btnGo.AddComponent<RectTransform>();
        btnRect.anchorMin = new Vector2(0.72f, 0);
        btnRect.anchorMax = new Vector2(1, 1);
        btnRect.offsetMin = new Vector2(0, 10);
        btnRect.offsetMax = new Vector2(-10, -10);

        var btnImage = btnGo.AddComponent<UnityEngine.UI.Image>();
        btnImage.color = new Color(0.3f, 0.6f, 1f, 1f);
        var btn = btnGo.AddComponent<UnityEngine.UI.Button>();
        btn.targetGraphic = btnImage;

        var btnTextGo = new GameObject("Text");
        btnTextGo.transform.SetParent(btnGo.transform, false);
        var btnTextRect = btnTextGo.AddComponent<RectTransform>();
        btnTextRect.anchorMin = Vector2.zero;
        btnTextRect.anchorMax = Vector2.one;
        btnTextRect.offsetMin = Vector2.zero;
        btnTextRect.offsetMax = Vector2.zero;
        var btnText = btnTextGo.AddComponent<TextMeshProUGUI>();
        btnText.text = "OK";
        btnText.fontSize = 16;
        btnText.alignment = TextAlignmentOptions.Center;
        btnText.color = Color.white;

        return panel;
    }

    private static void EnsureFolder(string path)
    {
        if (!AssetDatabase.IsValidFolder(path))
        {
            string[] parts = path.Split('/');
            string current = parts[0];
            for (int i = 1; i < parts.Length; i++)
            {
                string next = current + "/" + parts[i];
                if (!AssetDatabase.IsValidFolder(next))
                    AssetDatabase.CreateFolder(current, parts[i]);
                current = next;
            }
        }
    }
}
