using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;

/// Controller for notebook page 2 (SoundBox). Not a Gtk.Window — same
/// arrangement as SettingsWindow: it drives widgets inside the shared root.
public class SoundWindow
{
    [UI] private Label  ConditionNameLabel   = null;
    [UI] private Grid   SoundButtonGrid = null;
    [UI] private Button SoundBackButton = null;

    private const int Columns = 2;

    private readonly List<CaseDefinition> _allCases;
    private readonly List<string> _path = new List<string>();

    /// Raised when the drill-down reaches a leaf case.
    public event EventHandler<CaseDefinition> CaseSelected;

    /// Raised when Back is pressed at the top level.
    public event EventHandler BackRequested;

    public SoundWindow(Builder builder)
    {
        builder.Autoconnect(this);
        if (ConditionNameLabel == null || SoundButtonGrid == null || SoundBackButton == null)
            throw new InvalidOperationException(
                "Glade id mismatch — ConditionNameLabel=" + (ConditionNameLabel != null) +
                " SoundButtonGrid=" + (SoundButtonGrid != null) +
                " SoundBackButton=" + (SoundBackButton != null));

        _allCases = CaseDefinition.LoadCasesFromCsv(AppFile("cases.csv"));
        if (_allCases.Count == 0)
            Console.WriteLine("WARNING: no cases loaded — check cases.csv");

        SoundBackButton.Clicked += OnBackClicked;
    }

    /// Call every time the page becomes visible.
    public void Reset()
    {
        _path.Clear();
        Render();
    }

    /// Resolve next to the .exe, NOT the working directory.
    public static string AppFile(string relative)
    {
        string dir = Path.GetDirectoryName(
            System.Reflection.Assembly.GetExecutingAssembly().Location);
        return Path.Combine(dir, relative);
    }

    // ── one method covers all three levels ─────────────────────────────

    private void Render()
    {
        var matches = _allCases.Where(MatchesPath).ToList();

        // Distinct values one level deeper than where we currently are.
        var options = matches
            .Where(c => c.TreePath.Length > _path.Count)
            .Select(c => c.TreePath[_path.Count])
            .Distinct()
            .ToList();

        ConditionNameLabel.Text = _path.Count == 0
            ? "種別を選択"
            : string.Join(" : ", _path);

        BuildButtons(options, picked =>
        {
            _path.Add(picked);

            // Landed on a leaf? Play it and stay put.
            var leaf = _allCases.FirstOrDefault(
                c => c.TreePath.Length == _path.Count && MatchesPath(c));

            if (leaf != null)
            {
                Play(leaf);
                _path.RemoveAt(_path.Count - 1);
                return;
            }

            Render();
        });
    }

    private bool MatchesPath(CaseDefinition c)
    {
        string[] p = c.TreePath;
        if (p.Length < _path.Count) return false;
        for (int i = 0; i < _path.Count; i++)
            if (!string.Equals(p[i], _path[i], StringComparison.Ordinal)) return false;
        return true;
    }

    private void BuildButtons(IEnumerable<string> labels, Action<string> onPick)
    {
        foreach (var child in SoundButtonGrid.Children)
        {
            SoundButtonGrid.Remove(child);
            child.Destroy();
        }

        int i = 0;
        foreach (string text in labels)
        {
            string captured = text;              // don't close over the loop variable
            var btn = new Button(captured);
            btn.Hexpand = true;
            btn.Clicked += (s, e) => onPick(captured);
            SoundButtonGrid.Attach(btn, i % Columns, i / Columns, 1, 1);
            i++;
        }

        SoundButtonGrid.ShowAll();               // widgets made in code start hidden
    }

    private void Play(CaseDefinition c)
    {
        if (string.IsNullOrWhiteSpace(c.SoundPath))
        {
            Console.WriteLine("No Sound_File for case " + c.Number);
            return;
        }

        WavePlayer.Stop();   // the map page owns audio from here on

        var h = CaseSelected;
        if (h != null) h(this, c);

        // string full = AppFile(c.SoundPath);      // "sound/SND200.wav" -> absolute
        // if (!File.Exists(full))
        // {
        //     Console.WriteLine("Sound file missing: " + full);
        //     return;
        // }

        // ConditionNameLabel.Text = string.Join(" : ", _path);
        // WavePlayer.Play(full);
    }

    private void OnBackClicked(object sender, EventArgs e)
    {
        if (_path.Count > 0)
        {
            _path.RemoveAt(_path.Count - 1);
            Render();
        }
        else
        {
            WavePlayer.Stop();
            if (BackRequested != null) BackRequested(this, EventArgs.Empty);
        }
    }
}