#if TOOLS
using Godot;

namespace Mr.BrickAdventures.Tools.CaLevelGenerator;

[Tool]
public partial class CaLevelGeneratorDock : Control
{
    public CaLevelGeneratorPlugin Plugin { get; set; }

    // Controls referenced in Task 8 wiring
    private OptionButton _layerDropdown;
    private OptionButton _terrainDropdown;
    private HBoxContainer _rawTileRow;
    private SpinBox _sourceIdSpin;
    private SpinBox _atlasXSpin;
    private SpinBox _atlasYSpin;
    private Button _caveBtn;
    private Button _platformBtn;
    private Button _terrainBtn;
    private SpinBox _widthSpin;
    private SpinBox _heightSpin;
    private SpinBox _offsetXSpin;
    private SpinBox _offsetYSpin;
    private HSlider _densitySlider;
    private Label _densityLabel;
    private HSlider _smoothPassSlider;
    private Label _smoothPassLabel;
    private CheckBox _borderCheck;
    private SpinBox _seedSpin;
    private Button _genBtn;
    private Button _smoothBtn;
    private Button _clearBtn;

    private CaMode _mode = CaMode.Cave;

    private System.Collections.Generic.List<TileMapLayer> _layers = new();
    private TileMapLayer _selectedLayer;

    public override void _Ready()
    {
        CustomMinimumSize = new Vector2(200, 0);
        var scroll = new ScrollContainer();
        scroll.SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect);
        scroll.SizeFlagsVertical = SizeFlags.ExpandFill;
        AddChild(scroll);

        var vbox = new VBoxContainer();
        vbox.SizeFlagsHorizontal = SizeFlags.ExpandFill;
        scroll.AddChild(vbox);

        // Target Layer
        vbox.AddChild(new Label { Text = "Target Layer" });
        _layerDropdown = new OptionButton();
        _layerDropdown.SizeFlagsHorizontal = SizeFlags.ExpandFill;
        vbox.AddChild(_layerDropdown);

        // Terrain
        vbox.AddChild(new Label { Text = "Terrain" });
        _terrainDropdown = new OptionButton();
        _terrainDropdown.SizeFlagsHorizontal = SizeFlags.ExpandFill;
        vbox.AddChild(_terrainDropdown);

        // Raw tile row (hidden when terrain is available)
        _rawTileRow = new HBoxContainer();
        _rawTileRow.Visible = false;
        _rawTileRow.AddChild(new Label { Text = "Src" });
        _sourceIdSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
        _rawTileRow.AddChild(_sourceIdSpin);
        _rawTileRow.AddChild(new Label { Text = "X" });
        _atlasXSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
        _rawTileRow.AddChild(_atlasXSpin);
        _rawTileRow.AddChild(new Label { Text = "Y" });
        _atlasYSpin = new SpinBox { MinValue = 0, MaxValue = 99, Value = 0 };
        _rawTileRow.AddChild(_atlasYSpin);
        vbox.AddChild(_rawTileRow);

        // Mode toggle
        vbox.AddChild(new Label { Text = "Mode" });
        var modeRow = new HBoxContainer();
        modeRow.SizeFlagsHorizontal = SizeFlags.ExpandFill;
        _caveBtn     = MakeModeButton("Cave",     () => SetMode(CaMode.Cave));
        _platformBtn = MakeModeButton("Platform", () => SetMode(CaMode.Platform));
        _terrainBtn  = MakeModeButton("Terrain",  () => SetMode(CaMode.Terrain));
        _caveBtn.ButtonPressed = true;
        modeRow.AddChild(_caveBtn);
        modeRow.AddChild(_platformBtn);
        modeRow.AddChild(_terrainBtn);
        vbox.AddChild(modeRow);

        vbox.AddChild(new HSeparator());

        // Width / Height
        var dimRow = new HBoxContainer();
        dimRow.AddChild(MakeSpinColumn("Width",  out _widthSpin,  5, 500, 40));
        dimRow.AddChild(MakeSpinColumn("Height", out _heightSpin, 5, 500, 22));
        vbox.AddChild(dimRow);

        // Offset X / Y
        var offRow = new HBoxContainer();
        offRow.AddChild(MakeSpinColumn("Offset X", out _offsetXSpin, -9999, 9999, 0));
        offRow.AddChild(MakeSpinColumn("Offset Y", out _offsetYSpin, -9999, 9999, 0));
        vbox.AddChild(offRow);

        // Fill Density
        var densHeader = new HBoxContainer();
        densHeader.AddChild(new Label { Text = "Fill Density", SizeFlagsHorizontal = SizeFlags.ExpandFill });
        _densityLabel = new Label { Text = "48%" };
        densHeader.AddChild(_densityLabel);
        vbox.AddChild(densHeader);
        _densitySlider = new HSlider { MinValue = 0, MaxValue = 100, Value = 48, Step = 1 };
        _densitySlider.ValueChanged += v => _densityLabel.Text = $"{(int)v}%";
        vbox.AddChild(_densitySlider);

        // Smoothing Passes
        var smoothHeader = new HBoxContainer();
        smoothHeader.AddChild(new Label { Text = "Smoothing Passes", SizeFlagsHorizontal = SizeFlags.ExpandFill });
        _smoothPassLabel = new Label { Text = "4" };
        smoothHeader.AddChild(_smoothPassLabel);
        vbox.AddChild(smoothHeader);
        _smoothPassSlider = new HSlider { MinValue = 0, MaxValue = 10, Value = 4, Step = 1 };
        _smoothPassSlider.ValueChanged += v => _smoothPassLabel.Text = $"{(int)v}";
        vbox.AddChild(_smoothPassSlider);

        // Border walls
        _borderCheck = new CheckBox { Text = "Solid border walls", ButtonPressed = true };
        vbox.AddChild(_borderCheck);

        // Seed
        vbox.AddChild(new Label { Text = "Seed" });
        var seedRow = new HBoxContainer();
        _seedSpin = new SpinBox { MinValue = 0, MaxValue = int.MaxValue, Value = 12345,
                                   AllowGreater = true, SizeFlagsHorizontal = SizeFlags.ExpandFill };
        var randBtn = new Button { Text = "🎲" };
        randBtn.Pressed += () => _seedSpin.Value = GD.Randi();
        seedRow.AddChild(_seedSpin);
        seedRow.AddChild(randBtn);
        vbox.AddChild(seedRow);

        vbox.AddChild(new HSeparator());

        // Action buttons
        _genBtn = new Button { Text = "▶ Generate", SizeFlagsHorizontal = SizeFlags.ExpandFill };
        vbox.AddChild(_genBtn);

        var actionRow = new HBoxContainer();
        actionRow.SizeFlagsHorizontal = SizeFlags.ExpandFill;
        _smoothBtn = new Button { Text = "✦ Smooth", SizeFlagsHorizontal = SizeFlags.ExpandFill };
        _clearBtn  = new Button { Text = "✕ Clear",  SizeFlagsHorizontal = SizeFlags.ExpandFill };
        actionRow.AddChild(_smoothBtn);
        actionRow.AddChild(_clearBtn);
        vbox.AddChild(actionRow);

        _layerDropdown.ItemSelected   += OnLayerSelected;
        _terrainDropdown.ItemSelected += _ => SaveSettings();
        _genBtn.Pressed    += OnGenerate;
        _smoothBtn.Pressed += OnSmooth;
        _clearBtn.Pressed  += OnClear;

        LoadSettings();
    }

    public void OnSceneChanged(Node sceneRoot)
    {
        ScanLayers(sceneRoot);
        RestoreLastLayer(sceneRoot?.SceneFilePath ?? "");
    }

    private void SetMode(CaMode mode)
    {
        _mode = mode;
        _caveBtn.ButtonPressed     = mode == CaMode.Cave;
        _platformBtn.ButtonPressed = mode == CaMode.Platform;
        _terrainBtn.ButtonPressed  = mode == CaMode.Terrain;
    }

    private static Button MakeModeButton(string text, System.Action onPressed)
    {
        var btn = new Button { Text = text, ToggleMode = true,
                               SizeFlagsHorizontal = SizeFlags.ExpandFill };
        btn.Pressed += onPressed;
        return btn;
    }

    private static Control MakeSpinColumn(string label, out SpinBox spin,
                                           double min, double max, double value)
    {
        var col = new VBoxContainer { SizeFlagsHorizontal = SizeFlags.ExpandFill };
        col.AddChild(new Label { Text = label });
        spin = new SpinBox { MinValue = min, MaxValue = max, Value = value,
                             SizeFlagsHorizontal = SizeFlags.ExpandFill };
        col.AddChild(spin);
        return col;
    }

    private void ScanLayers(Node root)
    {
        _layers.Clear();
        _layerDropdown.Clear();
        if (root == null) return;
        CollectLayers(root);
        foreach (var layer in _layers)
            _layerDropdown.AddItem(layer.Name);
        if (_layers.Count > 0) OnLayerSelected(0);
    }

    private void CollectLayers(Node node)
    {
        if (node is TileMapLayer layer) _layers.Add(layer);
        foreach (Node child in node.GetChildren()) CollectLayers(child);
    }

    private void OnLayerSelected(long index)
    {
        if (index < 0 || index >= _layers.Count) return;
        _selectedLayer = _layers[(int)index];
        PopulateTerrainDropdown(_selectedLayer);

        var sceneRoot = EditorInterface.Singleton.GetEditedSceneRoot();
        if (sceneRoot != null)
        {
            var key = $"ca_generator/last_layer_{sceneRoot.SceneFilePath}";
            EditorInterface.Singleton.GetEditorSettings()
                .SetSetting(key, _selectedLayer.GetPath().ToString());
        }
        SaveSettings();
    }

    private void RestoreLastLayer(string sceneFilePath)
    {
        if (string.IsNullOrEmpty(sceneFilePath) || _layers.Count == 0) return;
        var key = $"ca_generator/last_layer_{sceneFilePath}";
        var es  = EditorInterface.Singleton.GetEditorSettings();
        if (!es.HasSetting(key)) return;
        var path = es.GetSetting(key).AsString();
        for (int i = 0; i < _layers.Count; i++)
        {
            if (_layers[i].GetPath().ToString() == path)
            {
                _layerDropdown.Select(i);
                OnLayerSelected(i);
                return;
            }
        }
    }

    private void PopulateTerrainDropdown(TileMapLayer layer)
    {
        _terrainDropdown.Clear();
        var tileSet = layer.TileSet;
        bool hasTerrains = false;

        if (tileSet != null)
        {
            for (int ts = 0; ts < tileSet.GetTerrainSetsCount(); ts++)
            {
                for (int t = 0; t < tileSet.GetTerrainsCount(ts); t++)
                {
                    _terrainDropdown.AddItem(tileSet.GetTerrainName(ts, t));
                    _terrainDropdown.SetItemMetadata(
                        _terrainDropdown.ItemCount - 1,
                        Variant.From((ts << 16) | t));
                    hasTerrains = true;
                }
            }
        }

        _terrainDropdown.Visible = hasTerrains;
        _rawTileRow.Visible      = !hasTerrains;
    }

    private CaGeneratorSettings BuildSettings()
    {
        int terrainSet = -1, terrain = 0;
        if (_terrainDropdown.Visible && _terrainDropdown.ItemCount > 0)
        {
            int packed = _terrainDropdown.GetSelectedMetadata().AsInt32();
            terrainSet = packed >> 16;
            terrain    = packed & 0xFFFF;
        }

        return new CaGeneratorSettings
        {
            Mode            = _mode,
            Width           = (int)_widthSpin.Value,
            Height          = (int)_heightSpin.Value,
            Offset          = new Vector2I((int)_offsetXSpin.Value, (int)_offsetYSpin.Value),
            FillDensity     = (float)_densitySlider.Value / 100f,
            SmoothingPasses = (int)_smoothPassSlider.Value,
            BorderWalls     = _borderCheck.ButtonPressed,
            Seed            = (int)_seedSpin.Value,
            TerrainSet      = terrainSet,
            Terrain         = terrain,
            SourceId        = (int)_sourceIdSpin.Value,
            AtlasCoords     = new Vector2I((int)_atlasXSpin.Value, (int)_atlasYSpin.Value),
        };
    }

    private void OnGenerate()
    {
        if (_selectedLayer == null) return;
        var settings = BuildSettings();
        var grid     = CaGenerator.Generate(settings);
        TilemapPainter.Paint(_selectedLayer, grid, settings, Plugin.UndoRedo);
        SaveSettings();
    }

    private void OnSmooth()
    {
        if (_selectedLayer == null) return;
        TilemapPainter.Smooth(_selectedLayer, BuildSettings(), Plugin.UndoRedo);
    }

    private void OnClear()
    {
        if (_selectedLayer == null) return;
        TilemapPainter.Clear(_selectedLayer, BuildSettings(), Plugin.UndoRedo);
    }

    private void SaveSettings()
    {
        var es = EditorInterface.Singleton.GetEditorSettings();
        es.SetSetting("ca_generator/mode",             (int)_mode);
        es.SetSetting("ca_generator/width",            (int)_widthSpin.Value);
        es.SetSetting("ca_generator/height",           (int)_heightSpin.Value);
        es.SetSetting("ca_generator/offset_x",         (int)_offsetXSpin.Value);
        es.SetSetting("ca_generator/offset_y",         (int)_offsetYSpin.Value);
        es.SetSetting("ca_generator/fill_density",     _densitySlider.Value);
        es.SetSetting("ca_generator/smoothing_passes", (int)_smoothPassSlider.Value);
        es.SetSetting("ca_generator/border_walls",     _borderCheck.ButtonPressed);
        es.SetSetting("ca_generator/seed",             (int)_seedSpin.Value);
        es.SetSetting("ca_generator/source_id",        (int)_sourceIdSpin.Value);
        es.SetSetting("ca_generator/atlas_x",          (int)_atlasXSpin.Value);
        es.SetSetting("ca_generator/atlas_y",          (int)_atlasYSpin.Value);
    }

    private void LoadSettings()
    {
        var es = EditorInterface.Singleton.GetEditorSettings();
        if (es == null) return;

        SetMode((CaMode)(es.HasSetting("ca_generator/mode") ? es.GetSetting("ca_generator/mode").AsInt32() : 0));
        _widthSpin.Value        = es.HasSetting("ca_generator/width")            ? es.GetSetting("ca_generator/width").AsDouble()            : 40.0;
        _heightSpin.Value       = es.HasSetting("ca_generator/height")           ? es.GetSetting("ca_generator/height").AsDouble()           : 22.0;
        _offsetXSpin.Value      = es.HasSetting("ca_generator/offset_x")         ? es.GetSetting("ca_generator/offset_x").AsDouble()         : 0.0;
        _offsetYSpin.Value      = es.HasSetting("ca_generator/offset_y")         ? es.GetSetting("ca_generator/offset_y").AsDouble()         : 0.0;
        _densitySlider.Value    = es.HasSetting("ca_generator/fill_density")     ? es.GetSetting("ca_generator/fill_density").AsDouble()     : 48.0;
        _smoothPassSlider.Value = es.HasSetting("ca_generator/smoothing_passes") ? es.GetSetting("ca_generator/smoothing_passes").AsDouble() : 4.0;
        _borderCheck.ButtonPressed = es.HasSetting("ca_generator/border_walls") ? es.GetSetting("ca_generator/border_walls").AsBool() : true;
        _seedSpin.Value         = es.HasSetting("ca_generator/seed")             ? es.GetSetting("ca_generator/seed").AsDouble()             : 12345.0;

        _sourceIdSpin.Value = es.HasSetting("ca_generator/source_id") ? es.GetSetting("ca_generator/source_id").AsDouble() : 0.0;
        _atlasXSpin.Value   = es.HasSetting("ca_generator/atlas_x")   ? es.GetSetting("ca_generator/atlas_x").AsDouble()   : 0.0;
        _atlasYSpin.Value   = es.HasSetting("ca_generator/atlas_y")   ? es.GetSetting("ca_generator/atlas_y").AsDouble()   : 0.0;

        _densityLabel.Text    = $"{(int)_densitySlider.Value}%";
        _smoothPassLabel.Text = $"{(int)_smoothPassSlider.Value}";
    }
}
#endif
