using System;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;

namespace ZB.MOM.WW.OtOpcUa.Client.UI.Controls;

/// <summary>
/// A date/time range picker using formatted text boxes and preset duration buttons.
/// Text properties are two-way bound to TextBoxes via XAML; DateTime properties
/// are synced in code-behind.
/// </summary>
public partial class DateTimeRangePicker : UserControl
{
    private const string Format = "yyyy-MM-dd HH:mm:ss";

    public static readonly StyledProperty<DateTimeOffset?> StartDateTimeProperty =
        AvaloniaProperty.Register<DateTimeRangePicker, DateTimeOffset?>(
            nameof(StartDateTime), defaultBindingMode: Avalonia.Data.BindingMode.TwoWay);

    public static readonly StyledProperty<DateTimeOffset?> EndDateTimeProperty =
        AvaloniaProperty.Register<DateTimeRangePicker, DateTimeOffset?>(
            nameof(EndDateTime), defaultBindingMode: Avalonia.Data.BindingMode.TwoWay);

    public static readonly StyledProperty<string> StartTextProperty =
        AvaloniaProperty.Register<DateTimeRangePicker, string>(nameof(StartText), defaultValue: "");

    public static readonly StyledProperty<string> EndTextProperty =
        AvaloniaProperty.Register<DateTimeRangePicker, string>(nameof(EndText), defaultValue: "");

    private bool _isUpdating;

    /// <summary>Initializes a new instance of the <see cref="DateTimeRangePicker"/> class.</summary>
    public DateTimeRangePicker()
    {
        InitializeComponent();
    }

    /// <summary>Gets or sets the start date and time.</summary>
    public DateTimeOffset? StartDateTime
    {
        get => GetValue(StartDateTimeProperty);
        set => SetValue(StartDateTimeProperty, value);
    }

    /// <summary>Gets or sets the end date and time.</summary>
    public DateTimeOffset? EndDateTime
    {
        get => GetValue(EndDateTimeProperty);
        set => SetValue(EndDateTimeProperty, value);
    }

    /// <summary>Gets or sets the start date/time as formatted text.</summary>
    public string StartText
    {
        get => GetValue(StartTextProperty);
        set => SetValue(StartTextProperty, value);
    }

    /// <summary>Gets or sets the end date/time as formatted text.</summary>
    public string EndText
    {
        get => GetValue(EndTextProperty);
        set => SetValue(EndTextProperty, value);
    }

    /// <inheritdoc />
    protected override void OnLoaded(RoutedEventArgs e)
    {
        base.OnLoaded(e);

        var startInput = this.FindControl<TextBox>("StartInput");
        var endInput = this.FindControl<TextBox>("EndInput");

        if (startInput != null) startInput.LostFocus += OnStartLostFocus;
        if (endInput != null) endInput.LostFocus += OnEndLostFocus;

        var last5Min = this.FindControl<Button>("Last5MinBtn");
        var lastHour = this.FindControl<Button>("LastHourBtn");
        var lastDay = this.FindControl<Button>("LastDayBtn");
        var lastWeek = this.FindControl<Button>("LastWeekBtn");

        if (last5Min != null) last5Min.Click += (_, _) => ApplyPreset(TimeSpan.FromMinutes(5));
        if (lastHour != null) lastHour.Click += (_, _) => ApplyPreset(TimeSpan.FromHours(1));
        if (lastDay != null) lastDay.Click += (_, _) => ApplyPreset(TimeSpan.FromDays(1));
        if (lastWeek != null) lastWeek.Click += (_, _) => ApplyPreset(TimeSpan.FromDays(7));
    }

    /// <inheritdoc />
    protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
    {
        base.OnPropertyChanged(change);
        if (_isUpdating) return;

        if (change.Property == StartDateTimeProperty)
        {
            _isUpdating = true;
            StartText = StartDateTime?.UtcDateTime.ToString(Format) ?? "";
            _isUpdating = false;
        }
        else if (change.Property == EndDateTimeProperty)
        {
            _isUpdating = true;
            EndText = EndDateTime?.UtcDateTime.ToString(Format) ?? "";
            _isUpdating = false;
        }
    }

    private void OnStartLostFocus(object? sender, RoutedEventArgs e)
    {
        var startInput = this.FindControl<TextBox>("StartInput");
        if (startInput == null) return;

        if (TryParseDateTime(startInput.Text, out var dt))
        {
            _isUpdating = true;
            StartDateTime = dt;
            _isUpdating = false;
            startInput.Foreground = null;
        }
        else if (!string.IsNullOrWhiteSpace(startInput.Text))
        {
            startInput.Foreground = Brushes.Red;
        }
    }

    private void OnEndLostFocus(object? sender, RoutedEventArgs e)
    {
        var endInput = this.FindControl<TextBox>("EndInput");
        if (endInput == null) return;

        if (TryParseDateTime(endInput.Text, out var dt))
        {
            _isUpdating = true;
            EndDateTime = dt;
            _isUpdating = false;
            endInput.Foreground = null;
        }
        else if (!string.IsNullOrWhiteSpace(endInput.Text))
        {
            endInput.Foreground = Brushes.Red;
        }
    }

    private void ApplyPreset(TimeSpan span)
    {
        _isUpdating = true;
        try
        {
            var now = DateTimeOffset.UtcNow;
            StartDateTime = now - span;
            EndDateTime = now;
            StartText = StartDateTime.Value.UtcDateTime.ToString(Format);
            EndText = EndDateTime.Value.UtcDateTime.ToString(Format);
        }
        finally
        {
            _isUpdating = false;
        }
    }

    private static bool TryParseDateTime(string? text, out DateTimeOffset result)
    {
        result = default;
        if (string.IsNullOrWhiteSpace(text)) return false;

        if (DateTimeOffset.TryParseExact(text, Format, CultureInfo.InvariantCulture,
                DateTimeStyles.AssumeUniversal, out result))
            return true;

        return DateTimeOffset.TryParse(text, CultureInfo.InvariantCulture,
            DateTimeStyles.AssumeUniversal, out result);
    }
}
