using System.IO;
using LiveOpsExamples;
using TMPro;
using UnityEditor;
using UnityEngine;

namespace LiveOpsExamples.Editor
{
  /// <summary>
  /// Bakes the Cozy Collector gameplay prefabs. Idempotent: every prefab is
  /// rebuilt from code and saved over the same fixed asset path.
  /// </summary>
  public static partial class CozyCollectorBake
  {
    private const string PrefabFolderPath = "Assets/LiveOpsExamples/Prefabs";
    private const string SnackSpritePath = "Assets/LiveOpsExamples/Sprites/snack.png";

    private static readonly Color AccentColor = ParseHexColor("#FFD27D");

    [MenuItem("Tools/LiveOps/Bake Cozy Collector Prefabs")]
    public static void BakePrefabs()
    {
      EnsureAssetFolder(PrefabFolderPath);

      SaveBakedPrefab(BuildSnackPrefab(), $"{PrefabFolderPath}/Snack.prefab");
      SaveBakedPrefab(BuildScorePopupPrefab(), $"{PrefabFolderPath}/ScorePopup.prefab");
      SaveBakedPrefab(BuildCollectBurstPrefab(), $"{PrefabFolderPath}/CollectBurst.prefab");

      AssetDatabase.SaveAssets();
      Debug.Log($"Cozy Collector prefabs baked under {PrefabFolderPath}");
    }

    private static GameObject BuildSnackPrefab()
    {
      var go = new GameObject("Snack");

      var collider = go.AddComponent<CircleCollider2D>();
      collider.isTrigger = true;
      collider.radius = 0.3f;

      var renderer = go.AddComponent<SpriteRenderer>();
      var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(SnackSpritePath);
      if (sprite == null)
      {
        Debug.LogError($"CozyCollectorBake: sprite not found at {SnackSpritePath}");
      }
      else
      {
        renderer.sprite = sprite;
        // Phaser setDisplaySize(52, 52) at 100 PPU -> 0.52 x 0.52 world units.
        var scale = new Vector3(
          0.52f / sprite.bounds.size.x,
          0.52f / sprite.bounds.size.y,
          1f);
        go.transform.localScale = scale;
        // Phaser pickup radius = 0.42 * 52px ~= 0.22 world units; a circle
        // collider's world radius scales by the largest transform axis.
        collider.radius = 0.22f / Mathf.Max(scale.x, scale.y);
      }

      go.AddComponent<Snack>();
      return go;
    }

    private static GameObject BuildScorePopupPrefab()
    {
      var go = new GameObject("ScorePopup");

      var label = go.AddComponent<TextMeshPro>();
      AssignDefaultFont(label);
      label.text = "+10";
      label.fontSize = 2.5f;
      label.alignment = TextAlignmentOptions.Center;
      label.color = Color.white;

      var view = go.AddComponent<ScorePopupView>();
      WireObjectFields(view, ("label", label));
      return go;
    }

    private static GameObject BuildCollectBurstPrefab()
    {
      var go = new GameObject("CollectBurst");
      var particles = go.AddComponent<ParticleSystem>();

      var main = particles.main;
      main.duration = 0.5f;
      main.loop = false;
      main.playOnAwake = true;
      main.startLifetime = 0.45f;
      main.startSpeed = 2f;
      main.startSize = 0.15f;
      main.gravityModifier = 0f;
      main.startColor = AccentColor;
      main.stopAction = ParticleSystemStopAction.Destroy;

      var emission = particles.emission;
      emission.rateOverTime = 0f;
      emission.SetBursts(new[] { new ParticleSystem.Burst(0f, 9) });

      var shape = particles.shape;
      shape.shapeType = ParticleSystemShapeType.Sphere;
      shape.radius = 0.1f;

      var renderer = particles.GetComponent<ParticleSystemRenderer>();
      renderer.renderMode = ParticleSystemRenderMode.Billboard;
      var material = AssetDatabase.GetBuiltinExtraResource<Material>("Default-Particle.mat");
      if (material == null)
        material = AssetDatabase.GetBuiltinExtraResource<Material>("Sprites-Default.mat");
      if (material == null)
        Debug.LogWarning("CozyCollectorBake: no builtin particle material resolved, assign one manually.");
      else
        renderer.sharedMaterial = material;

      return go;
    }

    private static Color ParseHexColor(string hex)
    {
      return ColorUtility.TryParseHtmlString(hex, out var color) ? color : Color.magenta;
    }

    private static void EnsureAssetFolder(string folderPath)
    {
      if (AssetDatabase.IsValidFolder(folderPath))
        return;

      var parent = Path.GetDirectoryName(folderPath)?.Replace('\\', '/');
      if (!string.IsNullOrEmpty(parent))
        EnsureAssetFolder(parent);
      AssetDatabase.CreateFolder(parent, Path.GetFileName(folderPath));
    }

    private static void SaveBakedPrefab(GameObject go, string path)
    {
      PrefabUtility.SaveAsPrefabAsset(go, path);
      Object.DestroyImmediate(go);
    }

    private static void WireObjectFields(Object component, params (string Field, Object Value)[] fields)
    {
      var serialized = new SerializedObject(component);
      foreach (var (field, value) in fields)
      {
        var property = serialized.FindProperty(field);
        if (property == null)
        {
          Debug.LogError($"CozyCollectorBake: field '{field}' not found on {component.GetType().Name}");
          continue;
        }

        property.objectReferenceValue = value;
      }

      serialized.ApplyModifiedPropertiesWithoutUndo();
    }

    private static void AssignDefaultFont(TMP_Text text)
    {
      if (TMP_Settings.defaultFontAsset != null)
        text.font = TMP_Settings.defaultFontAsset;
      else
        Debug.LogWarning("CozyCollectorBake: TMP default font asset is not set, assign a font manually.");
    }
  }
}
