using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Platform.Storage;

namespace DsmTool;

public partial class MainWindow : Window
{
    private string? _lastHtml;
    private string? _lastOut;
    private DsmConfig _loaded = new();     // 마지막으로 로드된 설정(SampleMarkers 등 UI에 없는 값 보관)
    private string? _appliedIni;           // 이미 적용한 ini 경로

    public MainWindow()
    {
        InitializeComponent();

        // 범용 기본값 — 빌드 산출물만 제외, 내부 NuGet은 자동 감지
        ExcludeBox.Text = string.Join(Environment.NewLine, DsmConfig.DefaultExcludePaths);
        ComponentBox.Text = "";

        // 실행 시 대상 폴더에 현재 폴더 자동 삽입
        try
        {
            var cur = Directory.GetCurrentDirectory();
            if (Directory.Exists(cur)) RootBox.Text = cur;
        }
        catch { }

        Log("대상 폴더가 현재 폴더로 지정되었습니다. 필요 시 변경 후 [생성] 을 누르세요.");
        Log("팁: 대상 폴더(또는 exe 폴더)에 dsm.config.ini 가 있으면 자동으로 읽어 적용합니다.");
        TryAutoLoad(RootBox.Text);
    }

    private async void BrowseRoot(object? s, Avalonia.Interactivity.RoutedEventArgs e)
    {
        var p = await PickFolder("분석할 대상 폴더 선택");
        if (p != null) { RootBox.Text = p; TryAutoLoad(p); }
    }

    // ini 자동 탐색·로드 (대상 폴더 → exe 폴더). 이미 적용한 파일이면 다시 안 함(사용자 수정 보존).
    private void TryAutoLoad(string? root)
    {
        if (string.IsNullOrWhiteSpace(root)) return;
        var ini = Program.FindConfig(root.Trim().Trim('"'));
        if (ini != null && !string.Equals(ini, _appliedIni, StringComparison.OrdinalIgnoreCase))
            LoadConfigFile(ini);
    }

    private async void LoadConfig(object? s, Avalonia.Interactivity.RoutedEventArgs e)
    {
        var top = GetTopLevel(this);
        if (top is null) return;
        var files = await top.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
        {
            Title = "dsm.config.ini 선택",
            AllowMultiple = false,
            FileTypeFilter = new[] { new FilePickerFileType("설정 (*.ini)") { Patterns = new[] { "*.ini" } } }
        });
        if (files.Count > 0) { var p = files[0].TryGetLocalPath(); if (p != null) LoadConfigFile(p); }
    }

    private void LoadConfigFile(string path)
    {
        try
        {
            var c = DsmConfig.Load(path);
            ExcludeBox.Text = string.Join(Environment.NewLine, c.ExcludePaths);
            SamplesBox.IsChecked = c.ExcludeSamples;
            AutoInternalBox.IsChecked = c.InternalAuto;
            FollowBox.IsChecked = c.FollowExternal;
            ExtDllBox.IsChecked = c.ExternalDlls;
            ComponentBox.Text = string.Join(Environment.NewLine, c.ManualMap.Select(kv => $"{kv.Key} = {kv.Value}"));
            foreach (var it in GroupCombo.Items)
                if (it is ContentControl cc && string.Equals(cc.Content?.ToString(), c.GroupMode, StringComparison.OrdinalIgnoreCase))
                { GroupCombo.SelectedItem = it; break; }
            _loaded = c; _appliedIni = path;
            Log("설정 적용됨: " + path);
        }
        catch (Exception ex) { Log("설정 로드 실패: " + ex.Message); }
    }

    private async void BrowseOut(object? s, Avalonia.Interactivity.RoutedEventArgs e)
    {
        var p = await PickFolder("출력 폴더 선택");
        if (p != null) OutBox.Text = p;
    }

    private async Task<string?> PickFolder(string title)
    {
        var top = GetTopLevel(this);
        if (top is null) return null;
        var res = await top.StorageProvider.OpenFolderPickerAsync(
            new FolderPickerOpenOptions { Title = title, AllowMultiple = false });
        return res.Count > 0 ? res[0].TryGetLocalPath() : null;
    }

    private async void Generate(object? s, Avalonia.Interactivity.RoutedEventArgs e)
    {
        var root = (RootBox.Text ?? "").Trim().Trim('"');
        if (string.IsNullOrWhiteSpace(root) || !Directory.Exists(root))
        {
            Log("⚠ 유효한 대상 폴더가 아닙니다: " + root);
            return;
        }
        var outDir = (OutBox.Text ?? "").Trim().Trim('"');
        if (string.IsNullOrWhiteSpace(outDir)) outDir = root;

        // 대상 폴더에 dsm.config.ini 가 있으면(아직 미적용) 자동 로드
        TryAutoLoad(root);

        var cfg = new DsmConfig
        {
            ExcludeSamples = SamplesBox.IsChecked == true,
            InternalAuto = AutoInternalBox.IsChecked == true,
            FollowExternal = FollowBox.IsChecked == true,
            ExternalDlls = ExtDllBox.IsChecked == true,
            GroupMode = (GroupCombo.SelectedItem as ContentControl)?.Content?.ToString() ?? "auto",
            ExcludePaths = SplitLines(ExcludeBox.Text).Select(x => x.ToLowerInvariant()).ToList(),
            ManualMap = ParseMap(SplitLines(ComponentBox.Text)),
            SampleMarkers = _loaded.SampleMarkers,   // UI에 없는 값(ini의 samplemarker)은 로드된 설정에서
        };
        if (cfg.ExcludePaths.Count == 0) cfg.ExcludePaths = DsmConfig.DefaultExcludePaths.ToList();

        GenBtn.IsEnabled = false;
        LogBox.Text = "";
        Log("분석 시작…  " + root);
        try
        {
            var r = await Task.Run(() => DsmEngine.Run(root, outDir, cfg, Log));
            _lastHtml = r.HtmlPath;
            _lastOut = outDir;
            OpenHtmlBtn.IsEnabled = true;
            OpenFolderBtn.IsEnabled = true;
            Log("");
            Log($"✔ 완료  노드 {r.Nodes} · 내부 간선 {r.Edges} · 순환(상삼각) 위반 {r.Upper}");
            Log($"  최다 Fan-in : {r.MaxFanIn} ({r.MaxFanInV})");
            Log($"  최다 Fan-out: {r.MaxFanOut} ({r.MaxFanOutV})");
            Log($"  → {r.HtmlPath}");
            Log($"  → {r.CsvPath}");
            if (r.Upper > 0) Log("  ⚠ 상삼각 위반 > 0 : 순환 의존이 존재합니다.");
        }
        catch (Exception ex)
        {
            Log("✘ 오류: " + ex.Message);
        }
        finally
        {
            GenBtn.IsEnabled = true;
        }
    }

    private void OpenHtml(object? s, Avalonia.Interactivity.RoutedEventArgs e)
    {
        if (_lastHtml != null && File.Exists(_lastHtml))
            Process.Start(new ProcessStartInfo { FileName = _lastHtml, UseShellExecute = true });
    }

    private void OpenFolder(object? s, Avalonia.Interactivity.RoutedEventArgs e)
    {
        if (_lastOut != null && Directory.Exists(_lastOut))
            Process.Start(new ProcessStartInfo { FileName = _lastOut, UseShellExecute = true });
    }

    private static Dictionary<string, string> ParseMap(IEnumerable<string> lines)
    {
        var d = new Dictionary<string, string>();
        foreach (var line in lines)
        {
            var i = line.IndexOf('=');
            if (i <= 0) continue;
            var k = line[..i].Trim().ToLowerInvariant();
            var v = line[(i + 1)..].Trim();
            if (k.Length > 0 && v.Length > 0) d[k] = v;
        }
        return d;
    }

    private static List<string> SplitLines(string? text)
    {
        var list = new List<string>();
        if (string.IsNullOrEmpty(text)) return list;
        foreach (var raw in text.Replace("\r", "").Split('\n'))
        {
            var t = raw.Trim();
            if (t.Length > 0) list.Add(t);
        }
        return list;
    }

    private void Log(string msg)
    {
        if (Avalonia.Threading.Dispatcher.UIThread.CheckAccess())
            LogBox.Text += msg + Environment.NewLine;
        else
            Avalonia.Threading.Dispatcher.UIThread.Post(() => LogBox.Text += msg + Environment.NewLine);
    }
}
