using System;
using System.IO;
using Microsoft.UI.Xaml.Media;
using Tornado3_2026Election.Common;
using Tornado3_2026Election.Domain;
using Tornado3_2026Election.Services;

namespace Tornado3_2026Election.ViewModels;

public sealed class CutListEntryViewModel : ObservableObject
{
    private readonly FormatTemplateDefinition _template;
    private readonly FormatCutDefinition _cut;
    private readonly Action<FormatTemplateDefinition> _durationChanged;
    private VideoWallLayoutPreset _videoWallLayoutPreset;
    private double _durationSeconds;
    private double _draftDurationSeconds;
    private double _thumbnailWidth;
    private double _thumbnailHeight;
    private ImageSource? _thumbnailSource;

    public CutListEntryViewModel(
        FormatTemplateDefinition template,
        FormatCutDefinition cut,
        Action<FormatTemplateDefinition> durationChanged,
        VideoWallLayoutPreset videoWallLayoutPreset)
    {
        _template = template;
        _cut = cut;
        _durationChanged = durationChanged;
        _videoWallLayoutPreset = videoWallLayoutPreset;
        _durationSeconds = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(cut.DurationSeconds, template);
        _draftDurationSeconds = _durationSeconds;
        _cut.DurationSeconds = _durationSeconds;
        _thumbnailSource = CutThumbnailAssetCatalog.CreateImageSource(template);
        IncreaseDurationCommand = new RelayCommand(IncreaseDraftDuration);
        DecreaseDurationCommand = new RelayCommand(DecreaseDraftDuration);
        ApplyDurationCommand = new RelayCommand(ApplyDraftDuration, CanApplyDraftDuration);
        ApplyThumbnailLayout();
    }

    public string FormatId => _template.Id;

    public string FormatName => _template.Name;

    public string CutName => _cut.Name;

    public string ChannelLabel => _template.RecommendedChannel switch
    {
        BroadcastChannel.Normal => "노멀",
        BroadcastChannel.TopLeft => "좌상단",
        BroadcastChannel.Bottom => "하단",
        BroadcastChannel.VideoWall => "비디오월",
        _ => _template.RecommendedChannel.ToString()
    };

    public string SourceFolder => Path.GetDirectoryName(_template.Id)?.Replace('\\', '/') ?? string.Empty;

    public string Description => _template.Description;

    public CutListElectionCategory ElectionCategory => CutListElectionCategoryResolver.Resolve(_template.Name);

    public string ElectionCategoryLabel => CutListElectionCategoryResolver.GetLabel(ElectionCategory);

    public bool IsInCategory(CutCategory category)
    {
        return CutCategoryResolver.IsMatch(_template, category);
    }

    public double MinimumDurationSeconds => ScheduleTemplatePolicy.GetMinimumCutDurationSeconds(_template);

    public RelayCommand IncreaseDurationCommand { get; }

    public RelayCommand DecreaseDurationCommand { get; }

    public RelayCommand ApplyDurationCommand { get; }

    public ImageSource? ThumbnailSource => _thumbnailSource;

    public bool HasThumbnail => CutThumbnailAssetCatalog.HasThumbnail(_template);

    public double ThumbnailWidth => _thumbnailWidth;

    public double ThumbnailHeight => _thumbnailHeight;

    public double DurationSeconds
    {
        get => _durationSeconds;
        set
        {
            var hadPendingDurationChange = HasPendingDurationChange;
            if (double.IsNaN(value) || double.IsInfinity(value))
            {
                return;
            }

            var normalized = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(value, _template);
            if (!SetProperty(ref _durationSeconds, normalized))
            {
                return;
            }

            if (Math.Abs(_cut.DurationSeconds - normalized) < 0.001d)
            {
                return;
            }

            _cut.DurationSeconds = normalized;
            if (!hadPendingDurationChange || _draftDurationSeconds <= 0)
            {
                SetProperty(ref _draftDurationSeconds, normalized, nameof(DraftDurationSeconds));
            }

            NotifyDurationStateChanged();
            _durationChanged(_template);
        }
    }

    public double DraftDurationSeconds
    {
        get => _draftDurationSeconds <= 0 ? DurationSeconds : _draftDurationSeconds;
        set
        {
            if (double.IsNaN(value) || double.IsInfinity(value))
            {
                return;
            }

            var normalized = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(value, _template);
            if (SetProperty(ref _draftDurationSeconds, normalized))
            {
                NotifyDurationStateChanged();
            }
        }
    }

    public bool HasPendingDurationChange => Math.Abs(DraftDurationSeconds - DurationSeconds) >= 0.001d;

    public string DurationApplyStatusLabel => HasPendingDurationChange ? "미적용" : "적용됨";

    public void RefreshFromSource()
    {
        var sourceValue = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(_cut.DurationSeconds, _template);
        _cut.DurationSeconds = sourceValue;
        if (Math.Abs(_durationSeconds - sourceValue) >= 0.001d)
        {
            SetProperty(ref _durationSeconds, sourceValue);
        }

        if (Math.Abs(_draftDurationSeconds - sourceValue) >= 0.001d)
        {
            SetProperty(ref _draftDurationSeconds, sourceValue, nameof(DraftDurationSeconds));
        }

        NotifyDurationStateChanged();
    }

    public void RefreshThumbnail()
    {
        _thumbnailSource = CutThumbnailAssetCatalog.CreateImageSource(_template);
        OnPropertyChanged(nameof(ThumbnailSource), nameof(HasThumbnail));
    }

    public void UpdateVideoWallLayoutPreset(VideoWallLayoutPreset videoWallLayoutPreset)
    {
        if (_videoWallLayoutPreset == videoWallLayoutPreset)
        {
            return;
        }

        _videoWallLayoutPreset = videoWallLayoutPreset;
        ApplyThumbnailLayout();
    }

    private void ApplyThumbnailLayout()
    {
        var metrics = ThumbnailLayoutResolver.ResolveDisplayMetrics(_template, _videoWallLayoutPreset, ThumbnailDisplayContext.CutList);
        SetProperty(ref _thumbnailWidth, metrics.Width, nameof(ThumbnailWidth));
        SetProperty(ref _thumbnailHeight, metrics.Height, nameof(ThumbnailHeight));
    }

    private void IncreaseDraftDuration()
    {
        DraftDurationSeconds += 1d;
    }

    private void DecreaseDraftDuration()
    {
        DraftDurationSeconds -= 1d;
    }

    private void ApplyDraftDuration()
    {
        DurationSeconds = DraftDurationSeconds;
        NotifyDurationStateChanged();
    }

    private bool CanApplyDraftDuration()
    {
        return HasPendingDurationChange;
    }

    private void NotifyDurationStateChanged()
    {
        OnPropertyChanged(nameof(HasPendingDurationChange), nameof(DurationApplyStatusLabel));
        ApplyDurationCommand.NotifyCanExecuteChanged();
    }
}
