import msgspec

from infrastructure.msgspec_fastapi import AppStruct


def _validate_range(value: int | float, field_name: str, minimum: int | float, maximum: int | float) -> None:
    if value < minimum or value > maximum:
        raise msgspec.ValidationError(f"{field_name} must be between {minimum} and {maximum}")


def _coerce_positive_int(value: object, field_name: str) -> int:
    if value is None:
        raise msgspec.ValidationError(f"{field_name} cannot be null")
    try:
        result = int(float(value))
    except (TypeError, ValueError) as exc:
        raise msgspec.ValidationError(f"Invalid integer value for {field_name}: {value}") from exc
    if result <= 0:
        raise msgspec.ValidationError(f"{field_name} must be positive")
    return result


def _mask_api_key(key: str) -> str:
    if len(key) > 3:
        return f"***...{key[-3:]}"
    return "***"


def _is_masked_api_key(value: str) -> bool:
    # Known limitation: a real key starting with "***" would be treated as masked
    # and discarded on save, preserving the previous key instead.
    return value.startswith("***")


class AdvancedSettings(AppStruct):
    cache_ttl_album_library: int = 86400
    cache_ttl_album_non_library: int = 21600
    cache_ttl_artist_library: int = 21600
    cache_ttl_artist_non_library: int = 21600
    cache_ttl_artist_discovery_library: int = 21600
    cache_ttl_artist_discovery_non_library: int = 3600
    cache_ttl_search: int = 3600
    cache_ttl_local_files_recently_added: int = 120
    cache_ttl_local_files_storage_stats: int = 300
    cache_ttl_jellyfin_recently_played: int = 300
    cache_ttl_jellyfin_favorites: int = 300
    cache_ttl_jellyfin_genres: int = 3600
    cache_ttl_jellyfin_library_stats: int = 600
    cache_ttl_navidrome_albums: int = 300
    cache_ttl_navidrome_artists: int = 300
    cache_ttl_navidrome_recent: int = 120
    cache_ttl_navidrome_favorites: int = 120
    cache_ttl_navidrome_search: int = 120
    cache_ttl_navidrome_genres: int = 3600
    cache_ttl_navidrome_stats: int = 600
    cache_ttl_plex_albums: int = 300
    cache_ttl_plex_search: int = 120
    cache_ttl_plex_genres: int = 3600
    cache_ttl_plex_stats: int = 600
    http_timeout: int = 10
    http_connect_timeout: int = 5
    http_max_connections: int = 200
    batch_artist_images: int = 10
    batch_albums: int = 8
    delay_artist: float = 0.5
    delay_albums: float = 0.3
    artist_discovery_warm_interval: int = 14400
    artist_discovery_warm_delay: float = 0.5
    artist_discovery_precache_delay: float = 0.2
    artist_discovery_precache_concurrency: int = 5
    memory_cache_max_entries: int = 10000
    memory_cache_cleanup_interval: int = 300
    cover_memory_cache_max_entries: int = 128
    cover_memory_cache_max_size_mb: int = 16
    disk_cache_cleanup_interval: int = 600
    recent_metadata_max_size_mb: int = 500
    recent_covers_max_size_mb: int = 1024
    persistent_metadata_ttl_hours: int = 24
    musicbrainz_concurrent_searches: int = 6
    discover_queue_size: int = 10
    discover_queue_ttl: int = 86400
    discover_queue_auto_generate: bool = True
    discover_queue_polling_interval: int = 4000
    discover_queue_warm_cycle_build: bool = True
    discover_queue_seed_artists: int = 3
    discover_queue_wildcard_slots: int = 2
    discover_queue_similar_artists_limit: int = 15
    discover_queue_albums_per_similar: int = 5
    discover_queue_enrich_ttl: int = 86400
    discover_queue_lastfm_mbid_max_lookups: int = 10
    frontend_ttl_home: int = 300000
    frontend_ttl_discover: int = 1800000
    frontend_ttl_library: int = 300000
    frontend_ttl_recently_added: int = 300000
    frontend_ttl_discover_queue: int = 86400000
    frontend_ttl_search: int = 300000
    frontend_ttl_local_files_sidebar: int = 120000
    frontend_ttl_jellyfin_sidebar: int = 120000
    frontend_ttl_plex_sidebar: int = 120000
    frontend_ttl_playlist_sources: int = 900000
    audiodb_enabled: bool = True
    audiodb_name_search_fallback: bool = False
    direct_remote_images_enabled: bool = True
    audiodb_api_key: str = "123"
    cache_ttl_audiodb_found: int = 604800
    cache_ttl_audiodb_not_found: int = 86400
    cache_ttl_audiodb_library: int = 1209600
    cache_ttl_recently_viewed_bytes: int = 172800
    sync_stall_timeout_minutes: int = 10
    sync_max_timeout_hours: int = 8
    audiodb_prewarm_concurrency: int = 4
    audiodb_prewarm_delay: float = 0.3
    genre_section_ttl: int = 21600
    request_concurrency: int = 2
    request_history_retention_days: int = 180
    ignored_releases_retention_days: int = 365
    orphan_cover_demote_interval_hours: int = 24
    store_prune_interval_hours: int = 6

    def __post_init__(self) -> None:
        if not self.audiodb_api_key or not self.audiodb_api_key.strip():
            self.audiodb_api_key = "123"
        ranges: dict[str, tuple[int | float, int | float]] = {
            "cache_ttl_album_library": (3600, 604800),
            "cache_ttl_album_non_library": (60, 86400),
            "cache_ttl_artist_library": (3600, 604800),
            "cache_ttl_artist_non_library": (3600, 604800),
            "cache_ttl_artist_discovery_library": (3600, 604800),
            "cache_ttl_artist_discovery_non_library": (3600, 604800),
            "cache_ttl_search": (60, 86400),
            "cache_ttl_local_files_recently_added": (60, 3600),
            "cache_ttl_local_files_storage_stats": (60, 3600),
            "cache_ttl_jellyfin_recently_played": (60, 3600),
            "cache_ttl_jellyfin_favorites": (60, 3600),
            "cache_ttl_jellyfin_genres": (60, 86400),
            "cache_ttl_jellyfin_library_stats": (60, 3600),
            "cache_ttl_navidrome_albums": (60, 3600),
            "cache_ttl_navidrome_artists": (60, 3600),
            "cache_ttl_navidrome_recent": (60, 3600),
            "cache_ttl_navidrome_favorites": (60, 3600),
            "cache_ttl_navidrome_search": (60, 3600),
            "cache_ttl_navidrome_genres": (60, 86400),
            "cache_ttl_navidrome_stats": (60, 3600),
            "cache_ttl_plex_albums": (60, 3600),
            "cache_ttl_plex_search": (60, 3600),
            "cache_ttl_plex_genres": (60, 86400),
            "cache_ttl_plex_stats": (60, 3600),
            "http_timeout": (5, 60),
            "http_connect_timeout": (1, 30),
            "http_max_connections": (50, 500),
            "batch_artist_images": (1, 20),
            "batch_albums": (1, 20),
            "delay_artist": (0.0, 5.0),
            "delay_albums": (0.0, 5.0),
            "artist_discovery_warm_interval": (300, 604800),
            "artist_discovery_warm_delay": (0.0, 5.0),
            "artist_discovery_precache_delay": (0.0, 5.0),
            "memory_cache_max_entries": (1000, 100000),
            "memory_cache_cleanup_interval": (60, 3600),
            "cover_memory_cache_max_entries": (16, 2048),
            "cover_memory_cache_max_size_mb": (1, 1024),
            "disk_cache_cleanup_interval": (60, 3600),
            "recent_metadata_max_size_mb": (100, 5000),
            "recent_covers_max_size_mb": (100, 10000),
            "persistent_metadata_ttl_hours": (1, 168),
            "musicbrainz_concurrent_searches": (2, 10),
            "artist_discovery_precache_concurrency": (1, 8),
            "sync_stall_timeout_minutes": (2, 30),
            "sync_max_timeout_hours": (1, 48),
            "audiodb_prewarm_concurrency": (1, 8),
            "request_concurrency": (1, 5),
            "audiodb_prewarm_delay": (0.0, 5.0),
            "discover_queue_size": (1, 20),
            "discover_queue_ttl": (3600, 604800),
            "discover_queue_polling_interval": (1000, 30000),
            "discover_queue_seed_artists": (1, 10),
            "discover_queue_wildcard_slots": (0, 10),
            "discover_queue_similar_artists_limit": (5, 50),
            "discover_queue_albums_per_similar": (1, 20),
            "discover_queue_enrich_ttl": (3600, 604800),
            "discover_queue_lastfm_mbid_max_lookups": (1, 50),
            "frontend_ttl_home": (60000, 3600000),
            "frontend_ttl_discover": (60000, 86400000),
            "frontend_ttl_library": (60000, 3600000),
            "frontend_ttl_recently_added": (60000, 3600000),
            "frontend_ttl_discover_queue": (3600000, 604800000),
            "frontend_ttl_search": (60000, 3600000),
            "frontend_ttl_local_files_sidebar": (60000, 3600000),
            "frontend_ttl_jellyfin_sidebar": (60000, 3600000),
            "frontend_ttl_plex_sidebar": (60000, 3600000),
            "frontend_ttl_playlist_sources": (60000, 3600000),
            "cache_ttl_audiodb_found": (3600, 2592000),
            "cache_ttl_audiodb_not_found": (3600, 604800),
            "cache_ttl_audiodb_library": (86400, 2592000),
            "cache_ttl_recently_viewed_bytes": (3600, 604800),
            "genre_section_ttl": (3600, 604800),
            "request_history_retention_days": (30, 3650),
            "ignored_releases_retention_days": (30, 3650),
            "orphan_cover_demote_interval_hours": (1, 168),
            "store_prune_interval_hours": (1, 168),
        }
        for field_name, (minimum, maximum) in ranges.items():
            _validate_range(getattr(self, field_name), field_name, minimum, maximum)


class FrontendCacheTTLs(AppStruct):
    home: int = 300000
    discover: int = 1800000
    library: int = 300000
    recently_added: int = 300000
    discover_queue: int = 86400000
    search: int = 300000
    local_files_sidebar: int = 120000
    jellyfin_sidebar: int = 120000
    plex_sidebar: int = 120000
    playlist_sources: int = 900000
    discover_queue_polling_interval: int = 4000
    discover_queue_auto_generate: bool = True


class AdvancedSettingsFrontend(AppStruct):
    cache_ttl_album_library: int = 24
    cache_ttl_album_non_library: int = 6
    cache_ttl_artist_library: int = 6
    cache_ttl_artist_non_library: int = 6
    cache_ttl_artist_discovery_library: int = 6
    cache_ttl_artist_discovery_non_library: int = 1
    cache_ttl_search: int = 60
    cache_ttl_local_files_recently_added: int = 2
    cache_ttl_local_files_storage_stats: int = 5
    cache_ttl_jellyfin_recently_played: int = 5
    cache_ttl_jellyfin_favorites: int = 5
    cache_ttl_jellyfin_genres: int = 60
    cache_ttl_jellyfin_library_stats: int = 10
    cache_ttl_navidrome_albums: int = 5
    cache_ttl_navidrome_artists: int = 5
    cache_ttl_navidrome_recent: int = 2
    cache_ttl_navidrome_favorites: int = 2
    cache_ttl_navidrome_search: int = 2
    cache_ttl_navidrome_genres: int = 60
    cache_ttl_navidrome_stats: int = 10
    cache_ttl_plex_albums: int = 5
    cache_ttl_plex_search: int = 2
    cache_ttl_plex_genres: int = 60
    cache_ttl_plex_stats: int = 10
    http_timeout: int = 10
    http_connect_timeout: int = 5
    http_max_connections: int = 200
    batch_artist_images: int = 10
    batch_albums: int = 8
    delay_artist: float = 0.5
    delay_albums: float = 0.3
    artist_discovery_warm_interval: int = 240
    artist_discovery_warm_delay: float = 0.5
    artist_discovery_precache_delay: float = 0.2
    memory_cache_max_entries: int = 10000
    memory_cache_cleanup_interval: int = 300
    cover_memory_cache_max_entries: int = 128
    cover_memory_cache_max_size_mb: int = 16
    disk_cache_cleanup_interval: int = 10
    recent_metadata_max_size_mb: int = 500
    recent_covers_max_size_mb: int = 1024
    persistent_metadata_ttl_hours: int = 24
    musicbrainz_concurrent_searches: int = 6
    discover_queue_size: int = 10
    discover_queue_ttl: int = 24
    discover_queue_auto_generate: bool = True
    discover_queue_polling_interval: int = 4
    discover_queue_warm_cycle_build: bool = True
    discover_queue_seed_artists: int = 3
    discover_queue_wildcard_slots: int = 2
    discover_queue_similar_artists_limit: int = 15
    discover_queue_albums_per_similar: int = 5
    discover_queue_enrich_ttl: int = 24
    discover_queue_lastfm_mbid_max_lookups: int = 10
    frontend_ttl_home: int = 5
    frontend_ttl_discover: int = 30
    frontend_ttl_library: int = 5
    frontend_ttl_recently_added: int = 5
    frontend_ttl_discover_queue: int = 1440
    frontend_ttl_search: int = 5
    frontend_ttl_local_files_sidebar: int = 2
    frontend_ttl_jellyfin_sidebar: int = 2
    frontend_ttl_plex_sidebar: int = 2
    frontend_ttl_playlist_sources: int = 15
    audiodb_enabled: bool = True
    audiodb_name_search_fallback: bool = False
    direct_remote_images_enabled: bool = True
    audiodb_api_key: str = "123"
    cache_ttl_audiodb_found: int = 168
    cache_ttl_audiodb_not_found: int = 24
    cache_ttl_audiodb_library: int = 336
    cache_ttl_recently_viewed_bytes: int = 48
    genre_section_ttl: int = 6
    request_history_retention_days: int = 180
    ignored_releases_retention_days: int = 365
    orphan_cover_demote_interval_hours: int = 24
    store_prune_interval_hours: int = 6
    sync_stall_timeout_minutes: int = 10
    sync_max_timeout_hours: int = 8
    audiodb_prewarm_concurrency: int = 4
    audiodb_prewarm_delay: float = 0.3
    request_concurrency: int = 2
    artist_discovery_precache_concurrency: int = 5

    def __post_init__(self) -> None:
        int_coerce_fields = [
            "cache_ttl_album_library",
            "cache_ttl_album_non_library",
            "cache_ttl_artist_library",
            "cache_ttl_artist_non_library",
            "cache_ttl_artist_discovery_library",
            "cache_ttl_artist_discovery_non_library",
            "cache_ttl_search",
            "cache_ttl_local_files_recently_added",
            "cache_ttl_local_files_storage_stats",
            "cache_ttl_jellyfin_recently_played",
            "cache_ttl_jellyfin_favorites",
            "cache_ttl_jellyfin_genres",
            "cache_ttl_jellyfin_library_stats",
            "cache_ttl_navidrome_albums",
            "cache_ttl_navidrome_artists",
            "cache_ttl_navidrome_recent",
            "cache_ttl_navidrome_favorites",
            "cache_ttl_navidrome_search",
            "cache_ttl_navidrome_genres",
            "cache_ttl_navidrome_stats",
            "cache_ttl_plex_albums",
            "cache_ttl_plex_search",
            "cache_ttl_plex_genres",
            "cache_ttl_plex_stats",
            "cache_ttl_audiodb_found",
            "cache_ttl_audiodb_not_found",
            "cache_ttl_audiodb_library",
            "cache_ttl_recently_viewed_bytes",
            "genre_section_ttl",
            "request_history_retention_days",
            "ignored_releases_retention_days",
            "orphan_cover_demote_interval_hours",
            "store_prune_interval_hours",
        ]
        for field_name in int_coerce_fields:
            setattr(self, field_name, _coerce_positive_int(getattr(self, field_name), field_name))

        ranges: dict[str, tuple[int | float, int | float]] = {
            "cache_ttl_album_library": (1, 168),
            "cache_ttl_album_non_library": (1, 24),
            "cache_ttl_artist_library": (1, 168),
            "cache_ttl_artist_non_library": (1, 168),
            "cache_ttl_artist_discovery_library": (1, 168),
            "cache_ttl_artist_discovery_non_library": (1, 168),
            "cache_ttl_search": (1, 1440),
            "cache_ttl_local_files_recently_added": (1, 60),
            "cache_ttl_local_files_storage_stats": (1, 60),
            "cache_ttl_jellyfin_recently_played": (1, 60),
            "cache_ttl_jellyfin_favorites": (1, 60),
            "cache_ttl_jellyfin_genres": (1, 1440),
            "cache_ttl_jellyfin_library_stats": (1, 60),
            "cache_ttl_navidrome_albums": (1, 60),
            "cache_ttl_navidrome_artists": (1, 60),
            "cache_ttl_navidrome_recent": (1, 60),
            "cache_ttl_navidrome_favorites": (1, 60),
            "cache_ttl_navidrome_search": (1, 60),
            "cache_ttl_navidrome_genres": (1, 1440),
            "cache_ttl_navidrome_stats": (1, 60),
            "cache_ttl_plex_albums": (1, 60),
            "cache_ttl_plex_search": (1, 60),
            "cache_ttl_plex_genres": (1, 1440),
            "cache_ttl_plex_stats": (1, 60),
            "http_timeout": (5, 60),
            "http_connect_timeout": (1, 30),
            "http_max_connections": (50, 500),
            "batch_artist_images": (1, 20),
            "batch_albums": (1, 20),
            "delay_artist": (0.0, 5.0),
            "delay_albums": (0.0, 5.0),
            "artist_discovery_warm_interval": (5, 10080),
            "artist_discovery_warm_delay": (0.0, 5.0),
            "artist_discovery_precache_delay": (0.0, 5.0),
            "memory_cache_max_entries": (1000, 100000),
            "memory_cache_cleanup_interval": (60, 3600),
            "cover_memory_cache_max_entries": (16, 2048),
            "cover_memory_cache_max_size_mb": (1, 1024),
            "disk_cache_cleanup_interval": (1, 60),
            "recent_metadata_max_size_mb": (100, 5000),
            "recent_covers_max_size_mb": (100, 10000),
            "persistent_metadata_ttl_hours": (1, 168),
            "musicbrainz_concurrent_searches": (2, 10),
            "discover_queue_size": (1, 20),
            "discover_queue_ttl": (1, 168),
            "discover_queue_polling_interval": (1, 30),
            "discover_queue_seed_artists": (1, 10),
            "discover_queue_wildcard_slots": (0, 10),
            "discover_queue_similar_artists_limit": (5, 50),
            "discover_queue_albums_per_similar": (1, 20),
            "discover_queue_enrich_ttl": (1, 168),
            "discover_queue_lastfm_mbid_max_lookups": (1, 50),
            "frontend_ttl_home": (1, 60),
            "frontend_ttl_discover": (1, 1440),
            "frontend_ttl_library": (1, 60),
            "frontend_ttl_recently_added": (1, 60),
            "frontend_ttl_discover_queue": (60, 10080),
            "frontend_ttl_search": (1, 60),
            "frontend_ttl_local_files_sidebar": (1, 60),
            "frontend_ttl_jellyfin_sidebar": (1, 60),
            "frontend_ttl_plex_sidebar": (1, 60),
            "frontend_ttl_playlist_sources": (1, 60),
            "cache_ttl_audiodb_found": (1, 720),
            "cache_ttl_audiodb_not_found": (1, 168),
            "cache_ttl_audiodb_library": (24, 720),
            "cache_ttl_recently_viewed_bytes": (1, 168),
            "genre_section_ttl": (1, 168),
            "request_history_retention_days": (30, 3650),
            "ignored_releases_retention_days": (30, 3650),
            "orphan_cover_demote_interval_hours": (1, 168),
            "store_prune_interval_hours": (1, 168),
            "sync_stall_timeout_minutes": (2, 30),
            "sync_max_timeout_hours": (1, 48),
            "audiodb_prewarm_concurrency": (1, 8),
            "request_concurrency": (1, 5),
            "audiodb_prewarm_delay": (0.0, 5.0),
            "artist_discovery_precache_concurrency": (1, 8),
        }
        for field_name, (minimum, maximum) in ranges.items():
            _validate_range(getattr(self, field_name), field_name, minimum, maximum)

    @staticmethod
    def from_backend(settings: AdvancedSettings) -> "AdvancedSettingsFrontend":
        return AdvancedSettingsFrontend(
            cache_ttl_album_library=settings.cache_ttl_album_library // 3600,
            cache_ttl_album_non_library=settings.cache_ttl_album_non_library // 3600,
            cache_ttl_artist_library=settings.cache_ttl_artist_library // 3600,
            cache_ttl_artist_non_library=settings.cache_ttl_artist_non_library // 3600,
            cache_ttl_artist_discovery_library=settings.cache_ttl_artist_discovery_library // 3600,
            cache_ttl_artist_discovery_non_library=settings.cache_ttl_artist_discovery_non_library // 3600,
            cache_ttl_search=settings.cache_ttl_search // 60,
            cache_ttl_local_files_recently_added=settings.cache_ttl_local_files_recently_added // 60,
            cache_ttl_local_files_storage_stats=settings.cache_ttl_local_files_storage_stats // 60,
            cache_ttl_jellyfin_recently_played=settings.cache_ttl_jellyfin_recently_played // 60,
            cache_ttl_jellyfin_favorites=settings.cache_ttl_jellyfin_favorites // 60,
            cache_ttl_jellyfin_genres=settings.cache_ttl_jellyfin_genres // 60,
            cache_ttl_jellyfin_library_stats=settings.cache_ttl_jellyfin_library_stats // 60,
            cache_ttl_navidrome_albums=settings.cache_ttl_navidrome_albums // 60,
            cache_ttl_navidrome_artists=settings.cache_ttl_navidrome_artists // 60,
            cache_ttl_navidrome_recent=settings.cache_ttl_navidrome_recent // 60,
            cache_ttl_navidrome_favorites=settings.cache_ttl_navidrome_favorites // 60,
            cache_ttl_navidrome_search=settings.cache_ttl_navidrome_search // 60,
            cache_ttl_navidrome_genres=settings.cache_ttl_navidrome_genres // 60,
            cache_ttl_navidrome_stats=settings.cache_ttl_navidrome_stats // 60,
            cache_ttl_plex_albums=settings.cache_ttl_plex_albums // 60,
            cache_ttl_plex_search=settings.cache_ttl_plex_search // 60,
            cache_ttl_plex_genres=settings.cache_ttl_plex_genres // 60,
            cache_ttl_plex_stats=settings.cache_ttl_plex_stats // 60,
            http_timeout=settings.http_timeout,
            http_connect_timeout=settings.http_connect_timeout,
            http_max_connections=settings.http_max_connections,
            batch_artist_images=settings.batch_artist_images,
            batch_albums=settings.batch_albums,
            delay_artist=settings.delay_artist,
            delay_albums=settings.delay_albums,
            artist_discovery_warm_interval=settings.artist_discovery_warm_interval // 60,
            artist_discovery_warm_delay=settings.artist_discovery_warm_delay,
            artist_discovery_precache_delay=settings.artist_discovery_precache_delay,
            memory_cache_max_entries=settings.memory_cache_max_entries,
            memory_cache_cleanup_interval=settings.memory_cache_cleanup_interval,
            cover_memory_cache_max_entries=settings.cover_memory_cache_max_entries,
            cover_memory_cache_max_size_mb=settings.cover_memory_cache_max_size_mb,
            disk_cache_cleanup_interval=settings.disk_cache_cleanup_interval // 60,
            recent_metadata_max_size_mb=settings.recent_metadata_max_size_mb,
            recent_covers_max_size_mb=settings.recent_covers_max_size_mb,
            persistent_metadata_ttl_hours=settings.persistent_metadata_ttl_hours,
            musicbrainz_concurrent_searches=settings.musicbrainz_concurrent_searches,
            discover_queue_size=settings.discover_queue_size,
            discover_queue_ttl=settings.discover_queue_ttl // 3600,
            discover_queue_auto_generate=settings.discover_queue_auto_generate,
            discover_queue_polling_interval=settings.discover_queue_polling_interval // 1000,
            discover_queue_warm_cycle_build=settings.discover_queue_warm_cycle_build,
            discover_queue_seed_artists=settings.discover_queue_seed_artists,
            discover_queue_wildcard_slots=settings.discover_queue_wildcard_slots,
            discover_queue_similar_artists_limit=settings.discover_queue_similar_artists_limit,
            discover_queue_albums_per_similar=settings.discover_queue_albums_per_similar,
            discover_queue_enrich_ttl=settings.discover_queue_enrich_ttl // 3600,
            discover_queue_lastfm_mbid_max_lookups=settings.discover_queue_lastfm_mbid_max_lookups,
            frontend_ttl_home=settings.frontend_ttl_home // 60000,
            frontend_ttl_discover=settings.frontend_ttl_discover // 60000,
            frontend_ttl_library=settings.frontend_ttl_library // 60000,
            frontend_ttl_recently_added=settings.frontend_ttl_recently_added // 60000,
            frontend_ttl_discover_queue=settings.frontend_ttl_discover_queue // 60000,
            frontend_ttl_search=settings.frontend_ttl_search // 60000,
            frontend_ttl_local_files_sidebar=settings.frontend_ttl_local_files_sidebar // 60000,
            frontend_ttl_jellyfin_sidebar=settings.frontend_ttl_jellyfin_sidebar // 60000,
            frontend_ttl_plex_sidebar=settings.frontend_ttl_plex_sidebar // 60000,
            frontend_ttl_playlist_sources=settings.frontend_ttl_playlist_sources // 60000,
            audiodb_enabled=settings.audiodb_enabled,
            audiodb_name_search_fallback=settings.audiodb_name_search_fallback,
            direct_remote_images_enabled=settings.direct_remote_images_enabled,
            audiodb_api_key=_mask_api_key(settings.audiodb_api_key),
            cache_ttl_audiodb_found=settings.cache_ttl_audiodb_found // 3600,
            cache_ttl_audiodb_not_found=settings.cache_ttl_audiodb_not_found // 3600,
            cache_ttl_audiodb_library=settings.cache_ttl_audiodb_library // 3600,
            cache_ttl_recently_viewed_bytes=settings.cache_ttl_recently_viewed_bytes // 3600,
            genre_section_ttl=settings.genre_section_ttl // 3600,
            request_history_retention_days=settings.request_history_retention_days,
            ignored_releases_retention_days=settings.ignored_releases_retention_days,
            orphan_cover_demote_interval_hours=settings.orphan_cover_demote_interval_hours,
            store_prune_interval_hours=settings.store_prune_interval_hours,
            sync_stall_timeout_minutes=settings.sync_stall_timeout_minutes,
            sync_max_timeout_hours=settings.sync_max_timeout_hours,
            audiodb_prewarm_concurrency=settings.audiodb_prewarm_concurrency,
            audiodb_prewarm_delay=settings.audiodb_prewarm_delay,
            request_concurrency=settings.request_concurrency,
            artist_discovery_precache_concurrency=settings.artist_discovery_precache_concurrency,
        )

    def to_backend(self) -> AdvancedSettings:
        return AdvancedSettings(
            cache_ttl_album_library=self.cache_ttl_album_library * 3600,
            cache_ttl_album_non_library=self.cache_ttl_album_non_library * 3600,
            cache_ttl_artist_library=self.cache_ttl_artist_library * 3600,
            cache_ttl_artist_non_library=self.cache_ttl_artist_non_library * 3600,
            cache_ttl_artist_discovery_library=self.cache_ttl_artist_discovery_library * 3600,
            cache_ttl_artist_discovery_non_library=self.cache_ttl_artist_discovery_non_library * 3600,
            cache_ttl_search=self.cache_ttl_search * 60,
            cache_ttl_local_files_recently_added=self.cache_ttl_local_files_recently_added * 60,
            cache_ttl_local_files_storage_stats=self.cache_ttl_local_files_storage_stats * 60,
            cache_ttl_jellyfin_recently_played=self.cache_ttl_jellyfin_recently_played * 60,
            cache_ttl_jellyfin_favorites=self.cache_ttl_jellyfin_favorites * 60,
            cache_ttl_jellyfin_genres=self.cache_ttl_jellyfin_genres * 60,
            cache_ttl_jellyfin_library_stats=self.cache_ttl_jellyfin_library_stats * 60,
            cache_ttl_navidrome_albums=self.cache_ttl_navidrome_albums * 60,
            cache_ttl_navidrome_artists=self.cache_ttl_navidrome_artists * 60,
            cache_ttl_navidrome_recent=self.cache_ttl_navidrome_recent * 60,
            cache_ttl_navidrome_favorites=self.cache_ttl_navidrome_favorites * 60,
            cache_ttl_navidrome_search=self.cache_ttl_navidrome_search * 60,
            cache_ttl_navidrome_genres=self.cache_ttl_navidrome_genres * 60,
            cache_ttl_navidrome_stats=self.cache_ttl_navidrome_stats * 60,
            cache_ttl_plex_albums=self.cache_ttl_plex_albums * 60,
            cache_ttl_plex_search=self.cache_ttl_plex_search * 60,
            cache_ttl_plex_genres=self.cache_ttl_plex_genres * 60,
            cache_ttl_plex_stats=self.cache_ttl_plex_stats * 60,
            http_timeout=self.http_timeout,
            http_connect_timeout=self.http_connect_timeout,
            http_max_connections=self.http_max_connections,
            batch_artist_images=self.batch_artist_images,
            batch_albums=self.batch_albums,
            delay_artist=self.delay_artist,
            delay_albums=self.delay_albums,
            artist_discovery_warm_interval=self.artist_discovery_warm_interval * 60,
            artist_discovery_warm_delay=self.artist_discovery_warm_delay,
            artist_discovery_precache_delay=self.artist_discovery_precache_delay,
            memory_cache_max_entries=self.memory_cache_max_entries,
            memory_cache_cleanup_interval=self.memory_cache_cleanup_interval,
            cover_memory_cache_max_entries=self.cover_memory_cache_max_entries,
            cover_memory_cache_max_size_mb=self.cover_memory_cache_max_size_mb,
            disk_cache_cleanup_interval=self.disk_cache_cleanup_interval * 60,
            recent_metadata_max_size_mb=self.recent_metadata_max_size_mb,
            recent_covers_max_size_mb=self.recent_covers_max_size_mb,
            persistent_metadata_ttl_hours=self.persistent_metadata_ttl_hours,
            musicbrainz_concurrent_searches=self.musicbrainz_concurrent_searches,
            discover_queue_size=self.discover_queue_size,
            discover_queue_ttl=self.discover_queue_ttl * 3600,
            discover_queue_auto_generate=self.discover_queue_auto_generate,
            discover_queue_polling_interval=self.discover_queue_polling_interval * 1000,
            discover_queue_warm_cycle_build=self.discover_queue_warm_cycle_build,
            discover_queue_seed_artists=self.discover_queue_seed_artists,
            discover_queue_wildcard_slots=self.discover_queue_wildcard_slots,
            discover_queue_similar_artists_limit=self.discover_queue_similar_artists_limit,
            discover_queue_albums_per_similar=self.discover_queue_albums_per_similar,
            discover_queue_enrich_ttl=self.discover_queue_enrich_ttl * 3600,
            discover_queue_lastfm_mbid_max_lookups=self.discover_queue_lastfm_mbid_max_lookups,
            frontend_ttl_home=self.frontend_ttl_home * 60000,
            frontend_ttl_discover=self.frontend_ttl_discover * 60000,
            frontend_ttl_library=self.frontend_ttl_library * 60000,
            frontend_ttl_recently_added=self.frontend_ttl_recently_added * 60000,
            frontend_ttl_discover_queue=self.frontend_ttl_discover_queue * 60000,
            frontend_ttl_search=self.frontend_ttl_search * 60000,
            frontend_ttl_local_files_sidebar=self.frontend_ttl_local_files_sidebar * 60000,
            frontend_ttl_jellyfin_sidebar=self.frontend_ttl_jellyfin_sidebar * 60000,
            frontend_ttl_plex_sidebar=self.frontend_ttl_plex_sidebar * 60000,
            frontend_ttl_playlist_sources=self.frontend_ttl_playlist_sources * 60000,
            audiodb_enabled=self.audiodb_enabled,
            audiodb_name_search_fallback=self.audiodb_name_search_fallback,
            direct_remote_images_enabled=self.direct_remote_images_enabled,
            audiodb_api_key=self.audiodb_api_key,
            cache_ttl_audiodb_found=self.cache_ttl_audiodb_found * 3600,
            cache_ttl_audiodb_not_found=self.cache_ttl_audiodb_not_found * 3600,
            cache_ttl_audiodb_library=self.cache_ttl_audiodb_library * 3600,
            cache_ttl_recently_viewed_bytes=self.cache_ttl_recently_viewed_bytes * 3600,
            genre_section_ttl=self.genre_section_ttl * 3600,
            request_history_retention_days=self.request_history_retention_days,
            ignored_releases_retention_days=self.ignored_releases_retention_days,
            orphan_cover_demote_interval_hours=self.orphan_cover_demote_interval_hours,
            store_prune_interval_hours=self.store_prune_interval_hours,
            sync_stall_timeout_minutes=self.sync_stall_timeout_minutes,
            sync_max_timeout_hours=self.sync_max_timeout_hours,
            audiodb_prewarm_concurrency=self.audiodb_prewarm_concurrency,
            audiodb_prewarm_delay=self.audiodb_prewarm_delay,
            request_concurrency=self.request_concurrency,
            artist_discovery_precache_concurrency=self.artist_discovery_precache_concurrency,
        )
