using System;
using System.Linq;
using System.Text.Json.Serialization;
using Microsoft.UI;
using Microsoft.UI.Xaml.Media;
using Tornado3_2026Election.Common;
using Tornado3_2026Election.Services;

namespace Tornado3_2026Election.Domain;

public sealed class ChannelScheduleItem : ObservableObject
{
    private ScheduleQueueItemState _state = ScheduleQueueItemState.Queued;
    private string _lastError = string.Empty;
    private DateTimeOffset? _lastPlayedAt;
    private string _currentRegionLabel = string.Empty;
    private double _defaultCutDurationSeconds;
    private double _draftCutDurationSeconds;
    private int _totalCuts;
    private double _thumbnailWidth = 160;
    private double _thumbnailHeight = 90;
    private ImageSource? _thumbnailSource;
    private string _renderedPreviewPath = string.Empty;
    private ImageSource? _renderedPreviewSource;
    private string _renderedPreviewStatusLabel = string.Empty;
    private string _internalNextPreviewPath = string.Empty;
    private ImageSource? _internalNextPreviewSource;
    private string _internalNextPreviewStatusLabel = string.Empty;
    private string _internalNextPreviewDisplayName = string.Empty;

    public Guid Id { get; set; } = Guid.NewGuid();

    public required string FormatId { get; init; }

    public required string FormatName { get; init; }

    public required string Description { get; init; }

    public required BroadcastChannel Channel { get; init; }

    public required bool RequiresImage { get; init; }

    public required double DefaultCutDurationSeconds
    {
        get => _defaultCutDurationSeconds;
        set
        {
            var hadPendingDurationChange = HasPendingDurationChange;
            var normalized = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(value, Channel, FormatName);
            if (SetProperty(ref _defaultCutDurationSeconds, normalized))
            {
                if (!hadPendingDurationChange || _draftCutDurationSeconds <= 0)
                {
                    SetProperty(ref _draftCutDurationSeconds, normalized, nameof(DraftCutDurationSeconds));
                }

                OnDurationStateChanged();
            }
        }
    }

    public double DraftCutDurationSeconds
    {
        get => _draftCutDurationSeconds <= 0 ? DefaultCutDurationSeconds : _draftCutDurationSeconds;
        set
        {
            var normalized = ScheduleTemplatePolicy.NormalizeCutDurationSeconds(value, Channel, FormatName);
            if (SetProperty(ref _draftCutDurationSeconds, normalized))
            {
                OnDurationStateChanged();
            }
        }
    }

    public required int TotalCuts
    {
        get => _totalCuts;
        set => SetProperty(ref _totalCuts, value);
    }

    public ScheduleRegionScope RegionScope { get; set; } = ScheduleRegionScope.All;

    public string ScheduleElectionType { get; set; } = string.Empty;

    public string RegionLabel { get; set; } = string.Empty;

    public string RegionCode { get; set; } = string.Empty;

    public ScheduleQueueItemState State
    {
        get => _state;
        set
        {
            var normalized = value == ScheduleQueueItemState.Completed
                ? ScheduleQueueItemState.Queued
                : value;
            if (SetProperty(ref _state, normalized))
            {
                OnPropertyChanged(nameof(StateLabel));
                OnPropertyChanged(nameof(StateBrush));
                OnPropertyChanged(nameof(StateCardBackgroundBrush));
                OnPropertyChanged(nameof(StateCardBorderBrush));
                OnPropertyChanged(nameof(StateBadgeBackgroundBrush));
                OnPropertyChanged(nameof(CardOpacity));
                OnPropertyChanged(nameof(CanDelete));
            }
        }
    }

    public string LastError
    {
        get => _lastError;
        set => SetProperty(ref _lastError, value);
    }

    public DateTimeOffset? LastPlayedAt
    {
        get => _lastPlayedAt;
        set => SetProperty(ref _lastPlayedAt, value);
    }

    public string CurrentRegionLabel
    {
        get => _currentRegionLabel;
        set
        {
            if (SetProperty(ref _currentRegionLabel, value))
            {
                OnPropertyChanged(nameof(DisplayRegionLabel));
                OnPropertyChanged(nameof(DisplayName));
            }
        }
    }

    [JsonIgnore]
    public string StateLabel => State switch
    {
        ScheduleQueueItemState.Next => "다음",
        ScheduleQueueItemState.Sending => "준비",
        ScheduleQueueItemState.OnAir => "송출 중",
        ScheduleQueueItemState.Completed => "대기",
        ScheduleQueueItemState.Error => "오류",
        _ => "대기"
    };

    [JsonIgnore]
    public SolidColorBrush StateBrush => new(State switch
    {
        ScheduleQueueItemState.Next => ColorHelper.FromArgb(255, 255, 184, 28),
        ScheduleQueueItemState.Sending => ColorHelper.FromArgb(255, 255, 132, 38),
        ScheduleQueueItemState.OnAir => ColorHelper.FromArgb(255, 239, 68, 68),
        ScheduleQueueItemState.Error => ColorHelper.FromArgb(255, 251, 113, 133),
        _ => ColorHelper.FromArgb(255, 100, 116, 139)
    });

    [JsonIgnore]
    public SolidColorBrush StateCardBackgroundBrush => new(State switch
    {
        ScheduleQueueItemState.Next => ColorHelper.FromArgb(255, 72, 38, 10),
        ScheduleQueueItemState.Sending => ColorHelper.FromArgb(255, 64, 42, 16),
        ScheduleQueueItemState.OnAir => ColorHelper.FromArgb(255, 58, 22, 24),
        ScheduleQueueItemState.Error => ColorHelper.FromArgb(255, 54, 18, 31),
        _ => ColorHelper.FromArgb(255, 18, 32, 51)
    });

    [JsonIgnore]
    public SolidColorBrush StateCardBorderBrush => new(State switch
    {
        ScheduleQueueItemState.Next => ColorHelper.FromArgb(255, 255, 184, 28),
        ScheduleQueueItemState.Sending => ColorHelper.FromArgb(255, 255, 132, 38),
        ScheduleQueueItemState.OnAir => ColorHelper.FromArgb(255, 255, 90, 84),
        ScheduleQueueItemState.Error => ColorHelper.FromArgb(255, 251, 113, 133),
        _ => ColorHelper.FromArgb(255, 39, 64, 95)
    });

    [JsonIgnore]
    public SolidColorBrush StateBadgeBackgroundBrush => new(State switch
    {
        ScheduleQueueItemState.Next => ColorHelper.FromArgb(255, 194, 65, 12),
        ScheduleQueueItemState.Sending => ColorHelper.FromArgb(255, 180, 83, 9),
        ScheduleQueueItemState.OnAir => ColorHelper.FromArgb(255, 220, 38, 38),
        ScheduleQueueItemState.Error => ColorHelper.FromArgb(255, 190, 18, 60),
        _ => ColorHelper.FromArgb(255, 26, 46, 71)
    });

    [JsonIgnore]
    public double CardOpacity => 1.0;

    [JsonIgnore]
    public bool CanDelete => State is not ScheduleQueueItemState.OnAir and not ScheduleQueueItemState.Sending;

    [JsonIgnore]
    public double MinimumDurationSeconds => ScheduleTemplatePolicy.GetMinimumCutDurationSeconds(Channel, FormatName);

    [JsonIgnore]
    public bool HasPendingDurationChange => Math.Abs(DraftCutDurationSeconds - DefaultCutDurationSeconds) >= 0.001d;

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

    [JsonIgnore]
    public string LastPlayedLabel => LastPlayedAt?.ToString("HH:mm:ss") ?? "아직 송출 전";

    [JsonIgnore]
    public string SelectionRegionLabel => RegionScope switch
    {
        ScheduleRegionScope.All => "전체",
        ScheduleRegionScope.StationRegions => "선택권역",
        ScheduleRegionScope.RegionGroup => string.IsNullOrWhiteSpace(RegionLabel) ? "시도" : RegionLabel,
        _ => string.IsNullOrWhiteSpace(RegionLabel) ? "개별 지역" : RegionLabel
    };

    [JsonIgnore]
    public string DisplayRegionLabel => string.IsNullOrWhiteSpace(CurrentRegionLabel)
        ? SelectionRegionLabel
        : CurrentRegionLabel;

    [JsonIgnore]
    public string DisplayName => $"{FormatName} / {DisplayRegionLabel}";

    [JsonIgnore]
    public ImageSource? ThumbnailSource => _thumbnailSource ??= CutThumbnailAssetCatalog.CreateImageSource(FormatId);

    [JsonIgnore]
    public bool HasThumbnail => CutThumbnailAssetCatalog.HasThumbnail(FormatId);

    [JsonIgnore]
    public ImageSource? PreviewSource => _renderedPreviewSource;

    [JsonIgnore]
    public bool HasRenderedPreview => _renderedPreviewSource is not null;

    [JsonIgnore]
    public string PreviewStatusLabel => HasRenderedPreview
        ? _renderedPreviewStatusLabel
        : string.IsNullOrWhiteSpace(_renderedPreviewStatusLabel)
            ? "실데이터 프리뷰 준비 중"
            : _renderedPreviewStatusLabel;

    [JsonIgnore]
    public ImageSource? InternalNextPreviewSource => _internalNextPreviewSource;

    [JsonIgnore]
    public bool HasInternalNextPreview => _internalNextPreviewSource is not null;

    [JsonIgnore]
    public string InternalNextPreviewStatusLabel => HasInternalNextPreview
        ? _internalNextPreviewStatusLabel
        : "다음 지역 프리뷰 준비 중";

    [JsonIgnore]
    public string InternalNextPreviewDisplayName => string.IsNullOrWhiteSpace(_internalNextPreviewDisplayName)
        ? DisplayName
        : _internalNextPreviewDisplayName;

    [JsonIgnore]
    public double ThumbnailWidth
    {
        get => _thumbnailWidth;
        private set => SetProperty(ref _thumbnailWidth, value);
    }

    [JsonIgnore]
    public double ThumbnailHeight
    {
        get => _thumbnailHeight;
        private set => SetProperty(ref _thumbnailHeight, value);
    }

    [JsonIgnore]
    public string ThumbnailStatusLabel => HasThumbnail ? "등록 썸네일" : "기본 아이콘";

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

    public void UpdateRenderedPreview(string previewPath, string statusLabel)
    {
        _renderedPreviewPath = previewPath;
        _renderedPreviewSource = CutPreviewAssetCatalog.CreateImageSource(previewPath);
        _renderedPreviewStatusLabel = statusLabel;
        OnPreviewChanged();
    }

    public void UpdateRenderedPreviewStatus(string statusLabel)
    {
        _renderedPreviewStatusLabel = statusLabel;
        OnPreviewChanged();
    }

    public void UpdateInternalNextPreview(string previewPath, string displayName, string statusLabel)
    {
        _internalNextPreviewPath = previewPath;
        _internalNextPreviewSource = CutPreviewAssetCatalog.CreateImageSource(previewPath);
        _internalNextPreviewDisplayName = displayName;
        _internalNextPreviewStatusLabel = statusLabel;
        OnInternalNextPreviewChanged();
    }

    public void ClearRenderedPreview()
    {
        if (string.IsNullOrWhiteSpace(_renderedPreviewPath) &&
            _renderedPreviewSource is null &&
            string.IsNullOrWhiteSpace(_renderedPreviewStatusLabel))
        {
            return;
        }

        _renderedPreviewPath = string.Empty;
        _renderedPreviewSource = null;
        _renderedPreviewStatusLabel = string.Empty;
        OnPreviewChanged();
    }

    public void ClearInternalNextPreview()
    {
        if (string.IsNullOrWhiteSpace(_internalNextPreviewPath) &&
            _internalNextPreviewSource is null &&
            string.IsNullOrWhiteSpace(_internalNextPreviewStatusLabel) &&
            string.IsNullOrWhiteSpace(_internalNextPreviewDisplayName))
        {
            return;
        }

        _internalNextPreviewPath = string.Empty;
        _internalNextPreviewSource = null;
        _internalNextPreviewStatusLabel = string.Empty;
        _internalNextPreviewDisplayName = string.Empty;
        OnInternalNextPreviewChanged();
    }

    public void UpdateThumbnailLayout(ThumbnailDisplayMetrics metrics)
    {
        ThumbnailWidth = metrics.Width;
        ThumbnailHeight = metrics.Height;
    }

    public void StepDraftDuration(double deltaSeconds)
    {
        DraftCutDurationSeconds = DraftCutDurationSeconds + deltaSeconds;
    }

    public void ApplyDraftDuration()
    {
        DefaultCutDurationSeconds = DraftCutDurationSeconds;
        OnDurationStateChanged();
    }

    private void OnDurationStateChanged()
    {
        OnPropertyChanged(nameof(HasPendingDurationChange));
        OnPropertyChanged(nameof(DurationApplyStatusLabel));
    }

    private void OnPreviewChanged()
    {
        OnPropertyChanged(nameof(PreviewSource));
        OnPropertyChanged(nameof(HasRenderedPreview));
        OnPropertyChanged(nameof(PreviewStatusLabel));
    }

    private void OnInternalNextPreviewChanged()
    {
        OnPropertyChanged(nameof(InternalNextPreviewSource));
        OnPropertyChanged(nameof(HasInternalNextPreview));
        OnPropertyChanged(nameof(InternalNextPreviewStatusLabel));
        OnPropertyChanged(nameof(InternalNextPreviewDisplayName));
    }

    public static ChannelScheduleItem FromTemplate(FormatTemplateDefinition template, ScheduleRegionOption? regionOption = null)
    {
        var selectedRegion = regionOption ?? new ScheduleRegionOption
        {
            Scope = ScheduleRegionScope.All,
            Label = "전체"
        };

        return new ChannelScheduleItem
        {
            FormatId = template.Id,
            FormatName = template.Name,
            Description = template.Description,
            Channel = template.RecommendedChannel,
            RequiresImage = template.RequiresImage,
            DefaultCutDurationSeconds = template.Cuts.First().DurationSeconds,
            TotalCuts = template.Cuts.Count,
            RegionScope = selectedRegion.Scope,
            ScheduleElectionType = selectedRegion.ElectionType,
            RegionLabel = selectedRegion.Scope is ScheduleRegionScope.Single or ScheduleRegionScope.RegionGroup
                ? selectedRegion.Label
                : string.Empty,
            RegionCode = selectedRegion.DistrictCode
        };
    }
}
