using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Threading;
using DragonISO.App.Services;

namespace DragonISO.App;

/// <summary>
/// Inline viewer for the daily show-notes file. Reads
/// <see cref="NotesService.TodayPath"/> on open and polls every 2s while
/// shown so REST/OSC-driven note appends surface live without the operator
/// having to click Refresh.
///
/// We don't allow editing here â€” the file is intentionally a one-way log
/// (operator stamps, post-show review). If someone wants to edit, they
/// click "Open in editor" and use Notepad.
/// </summary>
public partial class NotesWindow : Window
{
    private readonly DispatcherTimer _refreshTimer;
    private long _lastFileSize = -1;
    private DateTime _lastFileWrite = DateTime.MinValue;

    public NotesWindow()
    {
        InitializeComponent();
        _refreshTimer = new DispatcherTimer
        {
            Interval = TimeSpan.FromSeconds(2),
        };
        _refreshTimer.Tick += (_, _) => RefreshIfChanged();
        Loaded += (_, _) =>
        {
            DateLine.Text = $"{DateTimeOffset.Now:dddd, MMMM d, yyyy} Â· {NotesService.TodayPath}";
            ReloadFromDisk();
            _refreshTimer.Start();
        };
        Closed += (_, _) => _refreshTimer.Stop();
    }

    private void OnClose(object sender, RoutedEventArgs e) => Close();

    private void OnRefresh(object sender, RoutedEventArgs e) => ReloadFromDisk();

    /// <summary>
    /// Cheap mtime/size check â€” only re-reads the file when something changed.
    /// Saves the textbox a flicker on every 2s tick when no notes are being
    /// added. Falls through to a full reload if the file got smaller (operator
    /// might have edited externally).
    /// </summary>
    private void RefreshIfChanged()
    {
        try
        {
            var path = NotesService.TodayPath;
            if (!File.Exists(path)) return;
            var info = new FileInfo(path);
            if (info.Length != _lastFileSize || info.LastWriteTimeUtc != _lastFileWrite)
                ReloadFromDisk();
        }
        catch
        {
            // Disk hiccups shouldn't stop the timer.
        }
    }

    private void ReloadFromDisk()
    {
        try
        {
            var path = NotesService.TodayPath;
            if (!File.Exists(path))
            {
                NotesText.Text = "No notes yet. Stamp one via the REST or OSC endpoint and refresh.";
                return;
            }
            var info = new FileInfo(path);
            _lastFileSize = info.Length;
            _lastFileWrite = info.LastWriteTimeUtc;
            NotesText.Text = File.ReadAllText(path);
            // Scroll to bottom so the latest stamp is visible â€” operators are
            // typically reading "what just happened" not "what happened first."
            Dispatcher.BeginInvoke(new Action(() =>
            {
                Scroller.ScrollToEnd();
            }), DispatcherPriority.Background);
        }
        catch (Exception ex)
        {
            NotesText.Text = "Couldn't read notes file: " + ex.Message;
        }
    }

    /// <summary>
    /// Append the input box's text to today's notes file via NotesService,
    /// then clear the box and refresh the view. Bound to the "Add" button +
    /// Enter key in the input. Empty/whitespace input is a no-op.
    /// </summary>
    private void OnAddNote(object sender, RoutedEventArgs e)
    {
        var text = NewNoteBox.Text?.Trim();
        if (string.IsNullOrEmpty(text)) return;
        if (NotesService.Append(text))
        {
            NewNoteBox.Clear();
            ReloadFromDisk();
            NewNoteBox.Focus();
        }
    }

    /// <summary>Enter key in the input commits the note, same as the Add button.</summary>
    private void OnNewNoteKey(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == System.Windows.Input.Key.Enter)
        {
            OnAddNote(sender, e);
            e.Handled = true;
        }
    }

    private void OnOpenInEditor(object sender, RoutedEventArgs e)
    {
        try
        {
            Process.Start(new ProcessStartInfo
            {
                FileName = NotesService.TodayPath,
                UseShellExecute = true,
            });
        }
        catch
        {
            // Best-effort; if no .md handler is registered the OS shows its own dialog.
        }
    }
}
