using System.Collections.Generic;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Tornado3_2026Election.Common;
using Tornado3_2026Election.Domain;
using Tornado3_2026Election.Services;

namespace Tornado3_2026Election.ViewModels;

public sealed class SettingsViewModel : ObservableObject
{
    private string _selectedStationId = "KNN";
    private string _imageRootPath = TornadoPathResolver.GetDefaultT3CutPath();
    private bool _isDebugFeaturesEnabled;
    private int _normalLayerNo;
    private int _topLeftLayerNo = 1;
    private int _bottomLayerNo = 2;
    private int _videoWallLayerNo;
    private readonly IReadOnlyList<SelectionOption<VideoWallLayoutPreset>> _videoWallLayoutOptions =
    [
        new SelectionOption<VideoWallLayoutPreset>(VideoWallLayoutPreset.Auto, "자동"),
        new SelectionOption<VideoWallLayoutPreset>(VideoWallLayoutPreset.Wall3840x810, "3840 x 810"),
        new SelectionOption<VideoWallLayoutPreset>(VideoWallLayoutPreset.Wall2880x1080, "2880 x 1080"),
        new SelectionOption<VideoWallLayoutPreset>(VideoWallLayoutPreset.UltraWide8316x1080, "8316 x 1080")
    ];

    public SettingsViewModel(IEnumerable<BroadcastStationProfile> stations)
    {
        Stations = new ObservableCollection<StationFilterItemViewModel>(
            stations.Select(station => new StationFilterItemViewModel(station)));

        foreach (var station in Stations)
        {
            station.PropertyChanged += (_, args) =>
            {
                if (station == SelectedStation && args.PropertyName is nameof(StationFilterItemViewModel.RegionFiltersText) or nameof(StationFilterItemViewModel.RegionSelectionSummary))
                {
                    OnPropertyChanged(nameof(SelectedStationRegionSummary));
                }

                if (station == SelectedStation && args.PropertyName is nameof(StationFilterItemViewModel.VideoWallLayoutPreset) or nameof(StationFilterItemViewModel.VideoWallLayoutSummary))
                {
                    OnPropertyChanged(
                        nameof(SelectedStationVideoWallLayoutPreset),
                        nameof(SelectedStationVideoWallLayoutPresetSelection),
                        nameof(SelectedStationVideoWallLayoutSummary));
                }
            };
        }

        if (Stations.Count > 0)
        {
            _selectedStationId = Stations[0].Id;
        }
    }

    public ObservableCollection<StationFilterItemViewModel> Stations { get; }

    public IReadOnlyList<SelectionOption<VideoWallLayoutPreset>> VideoWallLayoutOptions => _videoWallLayoutOptions;

    public string SelectedStationId
    {
        get => _selectedStationId;
        set
        {
            if (SetProperty(ref _selectedStationId, value))
            {
                OnPropertyChanged(
                    nameof(SelectedStation),
                    nameof(SelectedStationLogoAssetPath),
                    nameof(SelectedStationRegions),
                    nameof(SelectedStationRegionSummary),
                    nameof(SelectedStationVideoWallLayoutPreset),
                    nameof(SelectedStationVideoWallLayoutPresetSelection),
                    nameof(SelectedStationVideoWallLayoutSummary));
            }
        }
    }

    public string ImageRootPath
    {
        get => TornadoPathResolver.GetDefaultT3CutPath();
        set => SetProperty(ref _imageRootPath, TornadoPathResolver.GetDefaultT3CutPath());
    }

    public bool IsDebugFeaturesEnabled
    {
        get => _isDebugFeaturesEnabled;
        set => SetProperty(ref _isDebugFeaturesEnabled, value);
    }

    public double NormalLayerNo
    {
        get => _normalLayerNo;
        set => SetLayerNo(ref _normalLayerNo, value, nameof(NormalLayerNo));
    }

    public double TopLeftLayerNo
    {
        get => _topLeftLayerNo;
        set => SetLayerNo(ref _topLeftLayerNo, value, nameof(TopLeftLayerNo));
    }

    public double BottomLayerNo
    {
        get => _bottomLayerNo;
        set => SetLayerNo(ref _bottomLayerNo, value, nameof(BottomLayerNo));
    }

    public double VideoWallLayerNo
    {
        get => _videoWallLayerNo;
        set => SetLayerNo(ref _videoWallLayerNo, value, nameof(VideoWallLayerNo));
    }

    public StationFilterItemViewModel SelectedStation
        => Stations.FirstOrDefault(station => station.Id == SelectedStationId) ?? Stations[0];

    public string SelectedStationLogoAssetPath => SelectedStation.LogoAssetPath;

    public ObservableCollection<RegionOptionViewModel> SelectedStationRegions => SelectedStation.Regions;

    public string SelectedStationRegionSummary => SelectedStation.RegionSelectionSummary;

    public VideoWallLayoutPreset SelectedStationVideoWallLayoutPreset
    {
        get => SelectedStation.VideoWallLayoutPreset;
        set
        {
            if (SelectedStation.VideoWallLayoutPreset == value)
            {
                return;
            }

            SelectedStation.VideoWallLayoutPreset = value;
            OnPropertyChanged(
                nameof(SelectedStationVideoWallLayoutPreset),
                nameof(SelectedStationVideoWallLayoutPresetSelection),
                nameof(SelectedStationVideoWallLayoutSummary));
        }
    }

    public VideoWallLayoutPreset? SelectedStationVideoWallLayoutPresetSelection
    {
        get => SelectedStationVideoWallLayoutPreset;
        set
        {
            if (value.HasValue)
            {
                SelectedStationVideoWallLayoutPreset = value.Value;
            }
        }
    }

    public string SelectedStationVideoWallLayoutSummary => SelectedStation.VideoWallLayoutSummary;

    public int GetKarismaLayerNo(BroadcastChannel channel)
    {
        return channel switch
        {
            BroadcastChannel.TopLeft => _topLeftLayerNo,
            BroadcastChannel.Bottom => _bottomLayerNo,
            BroadcastChannel.VideoWall => _videoWallLayerNo,
            _ => _normalLayerNo
        };
    }

    public BroadcastStationProfile BuildSelectedStationProfile()
    {
        return SelectedStation.ToProfile();
    }

    private void SetLayerNo(ref int field, double value, string propertyName)
    {
        SetProperty(ref field, NormalizeLayerNo(value), propertyName);
    }

    private static int NormalizeLayerNo(double value)
    {
        if (double.IsNaN(value) || double.IsInfinity(value))
        {
            return 0;
        }

        return Math.Clamp((int)Math.Round(value, MidpointRounding.AwayFromZero), 0, 99);
    }
}

