<?php
declare(strict_types=1);

namespace App\Models;

use PDO;

class Music extends BaseModel
{
    protected string $table = 'music_tracks';

    public function publishedPreview(int $limit = 6): array
    {
        return $this->list(['sort' => 'popular', 'limit' => $limit]);
    }

    public function latest(int $limit = 8): array
    {
        return $this->list(['sort' => 'newest', 'limit' => $limit]);
    }

    public function popular(int $limit = 8): array
    {
        return $this->list(['sort' => 'popular', 'limit' => $limit]);
    }

    public function featured(int $limit = 6): array
    {
        return $this->list(['sort' => 'featured', 'limit' => $limit]);
    }

    public function list(array $filters = []): array
    {
        $limit = min(max((int) ($filters['limit'] ?? 24), 1), 80);
        $offset = max((int) ($filters['offset'] ?? 0), 0);
        $sort = $this->normalizeSort((string) ($filters['sort'] ?? 'newest'));
        $where = ['mt.status = "published"'];
        $params = [];

        if (!empty($filters['q'])) {
            $query = '%' . trim((string) $filters['q']) . '%';
            $where[] = '(mt.title LIKE :q_title
                OR mt.artist_name LIKE :q_artist
                OR mt.description LIKE :q_description
                OR c.name LIKE :q_category
                OR EXISTS (
                    SELECT 1
                    FROM music_track_genres qmtg
                    INNER JOIN music_genres qmg ON qmg.id = qmtg.genre_id
                    WHERE qmtg.track_id = mt.id AND qmg.name LIKE :q_genre
                ))';
            $params['q_title'] = $query;
            $params['q_artist'] = $query;
            $params['q_description'] = $query;
            $params['q_category'] = $query;
            $params['q_genre'] = $query;
        }

        if (!empty($filters['genre_slug'])) {
            $where[] = 'EXISTS (
                SELECT 1
                FROM music_track_genres fmtg
                INNER JOIN music_genres fmg ON fmg.id = fmtg.genre_id
                WHERE fmtg.track_id = mt.id AND fmg.slug = :genre_slug
            )';
            $params['genre_slug'] = (string) $filters['genre_slug'];
        }

        if (!empty($filters['exclude_ids']) && is_array($filters['exclude_ids'])) {
            $ids = array_values(array_filter(array_map('intval', $filters['exclude_ids'])));
            if ($ids !== []) {
                $placeholders = [];
                foreach ($ids as $index => $id) {
                    $key = 'exclude_' . $index;
                    $placeholders[] = ':' . $key;
                    $params[$key] = $id;
                }
                $where[] = 'mt.id NOT IN (' . implode(',', $placeholders) . ')';
            }
        }

        if ($sort === 'premium') {
            $where[] = '(mt.privacy IN ("premium", "subscriber", "private") OR mt.package_id IS NOT NULL)';
        } elseif ($sort === 'free') {
            $where[] = '(mt.privacy IN ("public", "free") AND mt.package_id IS NULL)';
        }

        $order = match ($sort) {
            'popular', 'plays' => 'mt.play_count DESC, mt.like_count DESC, mt.created_at DESC',
            'liked' => 'mt.like_count DESC, mt.play_count DESC, mt.created_at DESC',
            'featured' => 'mt.featured DESC, mt.play_count DESC, mt.created_at DESC',
            'premium' => 'mt.featured DESC, mt.play_count DESC, mt.created_at DESC',
            'free' => 'mt.created_at DESC',
            default => 'mt.created_at DESC',
        };

        $statement = $this->db()->prepare(
            $this->selectSql() . '
             WHERE ' . implode(' AND ', $where) . "
             ORDER BY {$order}
             LIMIT :limit OFFSET :offset"
        );

        foreach ($params as $key => $value) {
            $statement->bindValue($key, $value, is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR);
        }
        $statement->bindValue('limit', $limit, PDO::PARAM_INT);
        $statement->bindValue('offset', $offset, PDO::PARAM_INT);
        $statement->execute();

        return array_map(fn (array $track): array => $this->normalize($track), $statement->fetchAll());
    }

    public function findBySlug(string $slug): ?array
    {
        $statement = $this->db()->prepare($this->selectSql() . ' WHERE mt.slug = :slug AND mt.status = "published" LIMIT 1');
        $statement->execute(['slug' => $slug]);
        $track = $statement->fetch();

        return $track ? $this->normalize($track) : null;
    }

    public function adminList(array $filters = [], int $limit = 120): array
    {
        $limit = min(max($limit, 1), 300);
        $where = [];
        $params = [];

        if (!empty($filters['q'])) {
            $where[] = '(mt.title LIKE :q_title OR mt.artist_name LIKE :q_artist OR mt.slug LIKE :q_slug OR u.username LIKE :q_user)';
            $like = '%' . trim((string) $filters['q']) . '%';
            $params['q_title'] = $like;
            $params['q_artist'] = $like;
            $params['q_slug'] = $like;
            $params['q_user'] = $like;
        }

        if (!empty($filters['genre_slug'])) {
            $where[] = 'EXISTS (
                SELECT 1
                FROM music_track_genres amt
                INNER JOIN music_genres amg ON amg.id = amt.genre_id
                WHERE amt.track_id = mt.id AND amg.slug = :genre_slug
            )';
            $params['genre_slug'] = (string) $filters['genre_slug'];
        }

        if (!empty($filters['status'])) {
            $where[] = 'mt.status = :status';
            $params['status'] = (string) $filters['status'];
        } else {
            $where[] = 'mt.status <> "archived"';
        }

        $premium = (string) ($filters['premium'] ?? '');
        if ($premium === 'premium') {
            $where[] = '(mt.privacy IN ("premium", "subscriber", "private") OR mt.package_id IS NOT NULL)';
        } elseif ($premium === 'free') {
            $where[] = '(mt.privacy IN ("public", "free") AND mt.package_id IS NULL)';
        }

        $sql = $this->selectSql();
        if ($where !== []) {
            $sql .= ' WHERE ' . implode(' AND ', $where);
        }
        $sql .= ' ORDER BY FIELD(mt.status, "pending", "draft", "published", "rejected", "archived"), mt.created_at DESC, mt.id DESC LIMIT :limit';

        $statement = $this->db()->prepare($sql);
        foreach ($params as $key => $value) {
            $statement->bindValue($key, $value, is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR);
        }
        $statement->bindValue('limit', $limit, PDO::PARAM_INT);
        $statement->execute();

        return array_map(fn (array $track): array => $this->normalize($track), $statement->fetchAll());
    }

    public function updateStatusByAdmin(int $id, string $status): void
    {
        $allowed = ['draft', 'pending', 'pending_review', 'published', 'rejected', 'blocked', 'archived'];
        if (!in_array($status, $allowed, true)) {
            throw new \InvalidArgumentException('Muzik durumu gecersiz.');
        }

        $statement = $this->db()->prepare('UPDATE music_tracks SET status = :status, updated_at = NOW() WHERE id = :id');
        $statement->execute(['status' => $status, 'id' => $id]);
    }

    public function setFeaturedByAdmin(int $id, bool $featured): void
    {
        $statement = $this->db()->prepare('UPDATE music_tracks SET featured = :featured, updated_at = NOW() WHERE id = :id');
        $statement->execute(['featured' => $featured ? 1 : 0, 'id' => $id]);
    }

    public function findPublishedById(int $id): ?array
    {
        $statement = $this->db()->prepare($this->selectSql() . ' WHERE mt.id = :id AND mt.status = "published" LIMIT 1');
        $statement->execute(['id' => $id]);
        $track = $statement->fetch();

        return $track ? $this->normalize($track) : null;
    }

    public function publishedForCreator(int $creatorId, int $limit = 24): array
    {
        if ($creatorId <= 0) {
            return [];
        }

        $limit = min(max($limit, 1), 60);
        $statement = $this->db()->prepare(
            $this->selectSql() . '
             WHERE mt.user_id = :creator_id
               AND mt.status IN ("published", "active")
               AND mt.privacy <> "private"
             ORDER BY mt.featured DESC, mt.created_at DESC, mt.id DESC
             LIMIT :limit'
        );
        $statement->bindValue('creator_id', $creatorId, PDO::PARAM_INT);
        $statement->bindValue('limit', $limit, PDO::PARAM_INT);
        $statement->execute();

        return array_map(fn (array $track): array => $this->normalize($track), $statement->fetchAll());
    }

    public function genres(): array
    {
        $statement = $this->db()->query(
            'SELECT mg.id, mg.name, mg.slug, mg.description, mg.icon, mg.banner, mg.sort_order, mg.created_at, mg.updated_at,
                    COUNT(DISTINCT CASE WHEN mt.status = "published" THEN mt.id END) AS track_count
             FROM music_genres mg
             LEFT JOIN music_track_genres mtg ON mtg.genre_id = mg.id
             LEFT JOIN music_tracks mt ON mt.id = mtg.track_id
             GROUP BY mg.id, mg.name, mg.slug, mg.description, mg.icon, mg.banner, mg.sort_order, mg.created_at, mg.updated_at
             ORDER BY mg.sort_order ASC, mg.name ASC'
        );

        return array_map(fn (array $genre): array => $this->normalizeGenre($genre), $statement->fetchAll());
    }

    public function genreBySlug(string $slug): ?array
    {
        $statement = $this->db()->prepare(
            'SELECT mg.id, mg.name, mg.slug, mg.description, mg.icon, mg.banner, mg.sort_order, mg.created_at, mg.updated_at,
                    COUNT(DISTINCT CASE WHEN mt.status = "published" THEN mt.id END) AS track_count
             FROM music_genres mg
             LEFT JOIN music_track_genres mtg ON mtg.genre_id = mg.id
             LEFT JOIN music_tracks mt ON mt.id = mtg.track_id
             WHERE mg.slug = :slug
             GROUP BY mg.id, mg.name, mg.slug, mg.description, mg.icon, mg.banner, mg.sort_order, mg.created_at, mg.updated_at
             LIMIT 1'
        );
        $statement->execute(['slug' => $slug]);
        $genre = $statement->fetch();

        return $genre ? $this->normalizeGenre($genre) : null;
    }

    public function featuredArtists(int $limit = 6): array
    {
        $limit = min(max($limit, 1), 24);
        $statement = $this->db()->prepare(
            'SELECT COALESCE(a.artist_name, mt.artist_name) AS artist_name,
                    COALESCE(a.slug, LOWER(REPLACE(mt.artist_name, " ", "-"))) AS slug,
                    COALESCE(a.avatar, MAX(mt.cover_image)) AS avatar,
                    COALESCE(a.cover_image, MAX(mt.cover_image)) AS cover_image,
                    MAX(a.verified) AS verified,
                    COUNT(*) AS track_count,
                    SUM(mt.play_count) AS play_count,
                    SUM(mt.like_count) AS like_count,
                    MAX(mt.user_id) AS user_id
             FROM music_tracks mt
             LEFT JOIN artists a ON a.id = mt.artist_id
             WHERE mt.status = "published"
             GROUP BY COALESCE(a.id, mt.artist_name), COALESCE(a.artist_name, mt.artist_name), COALESCE(a.slug, LOWER(REPLACE(mt.artist_name, " ", "-"))), a.avatar, a.cover_image
             ORDER BY SUM(mt.play_count) DESC, SUM(mt.like_count) DESC, artist_name ASC
             LIMIT :limit'
        );
        $statement->bindValue('limit', $limit, PDO::PARAM_INT);
        $statement->execute();

        return array_map(static function (array $artist): array {
            return [
                'name' => (string) ($artist['artist_name'] ?? 'Zalorox Music'),
                'slug' => (string) (($artist['slug'] ?? '') ?: 'artist'),
                'track_count' => (int) ($artist['track_count'] ?? 0),
                'play_count' => (int) ($artist['play_count'] ?? 0),
                'like_count' => (int) ($artist['like_count'] ?? 0),
                'avatar' => (string) (($artist['avatar'] ?? '') ?: (($artist['cover_image'] ?? '') ?: '/uploads/music-covers/track-1.svg')),
                'cover_image' => (string) (($artist['cover_image'] ?? '') ?: '/uploads/music-covers/track-1.svg'),
                'verified' => !empty($artist['verified']),
                'user_id' => isset($artist['user_id']) ? (int) $artist['user_id'] : null,
            ];
        }, $statement->fetchAll());
    }

    public function findArtistBySlug(string $slug): ?array
    {
        $statement = $this->db()->prepare(
            'SELECT a.*,
                    COUNT(mt.id) AS track_count,
                    COALESCE(SUM(mt.play_count), 0) AS play_count,
                    COALESCE(SUM(mt.like_count), 0) AS like_count
             FROM artists a
             LEFT JOIN music_tracks mt ON mt.artist_id = a.id AND mt.status = "published"
             WHERE a.slug = :slug
             GROUP BY a.id
             LIMIT 1'
        );
        $statement->execute(['slug' => $slug]);
        $artist = $statement->fetch();

        if (!$artist) {
            return null;
        }

        $artist['id'] = (int) ($artist['id'] ?? 0);
        $artist['user_id'] = isset($artist['user_id']) ? (int) $artist['user_id'] : null;
        $artist['verified'] = !empty($artist['verified']);
        $artist['track_count'] = (int) ($artist['track_count'] ?? 0);
        $artist['play_count'] = (int) ($artist['play_count'] ?? 0);
        $artist['like_count'] = (int) ($artist['like_count'] ?? 0);

        return $artist;
    }

    public function tracksForArtist(array $artist, int $limit = 40): array
    {
        $limit = min(max($limit, 1), 80);
        $artistId = (int) ($artist['id'] ?? 0);
        $artistName = (string) ($artist['artist_name'] ?? '');
        $statement = $this->db()->prepare(
            $this->selectSql() . '
             WHERE mt.status = "published"
               AND (mt.artist_id = :artist_id OR mt.artist_name = :artist_name)
             ORDER BY mt.featured DESC, mt.play_count DESC, mt.created_at DESC
             LIMIT :limit'
        );
        $statement->bindValue('artist_id', $artistId, PDO::PARAM_INT);
        $statement->bindValue('artist_name', $artistName, PDO::PARAM_STR);
        $statement->bindValue('limit', $limit, PDO::PARAM_INT);
        $statement->execute();

        return array_map(fn (array $track): array => $this->normalize($track), $statement->fetchAll());
    }

    public function related(array $track, int $limit = 6): array
    {
        $genreSlugs = array_filter(array_map('trim', explode(',', (string) ($track['genre_slugs'] ?? ''))));
        $filters = [
            'limit' => $limit,
            'sort' => 'popular',
            'exclude_ids' => [(int) ($track['id'] ?? 0)],
        ];

        if ($genreSlugs !== []) {
            $filters['genre_slug'] = $genreSlugs[0];
        }

        $related = $this->list($filters);

        if (count($related) < $limit) {
            $seen = array_merge([(int) ($track['id'] ?? 0)], array_map(static fn (array $item): int => (int) ($item['id'] ?? 0), $related));
            $related = array_merge($related, $this->list([
                'limit' => $limit - count($related),
                'sort' => 'popular',
                'exclude_ids' => $seen,
            ]));
        }

        return array_slice($related, 0, $limit);
    }

    public function recordView(int $trackId): void
    {
        $this->db()->prepare('UPDATE music_tracks SET view_count = view_count + 1 WHERE id = :id')->execute(['id' => $trackId]);
    }

    public function recordPlay(int $trackId, ?int $userId, ?string $ipAddress): array
    {
        $ipAddress = $ipAddress !== null ? substr($ipAddress, 0, 64) : null;
        $since = date('Y-m-d H:i:s', time() - 15 * 60);
        $params = [
            'track_id' => $trackId,
            'since' => $since,
        ];

        if ($userId !== null) {
            $recentSql = 'SELECT id FROM music_plays WHERE track_id = :track_id AND user_id = :user_id AND created_at >= :since LIMIT 1';
            $params['user_id'] = $userId;
        } else {
            $recentSql = 'SELECT id FROM music_plays WHERE track_id = :track_id AND user_id IS NULL AND ip_address = :ip_address AND created_at >= :since LIMIT 1';
            $params['ip_address'] = $ipAddress ?? '';
        }

        $recent = $this->db()->prepare($recentSql);
        $recent->execute($params);
        $counted = !$recent->fetchColumn();

        if ($counted) {
            $statement = $this->db()->prepare(
                'INSERT INTO music_plays (track_id, user_id, ip_address, created_at)
                 VALUES (:track_id, :user_id, :ip_address, NOW())'
            );
            $statement->execute([
                'track_id' => $trackId,
                'user_id' => $userId,
                'ip_address' => $ipAddress,
            ]);

            $this->db()->prepare('UPDATE music_tracks SET play_count = play_count + 1 WHERE id = :id')->execute(['id' => $trackId]);
        }

        return [
            'counted' => $counted,
            'play_count' => $this->playCount($trackId),
        ];
    }

    public function userLiked(int $trackId, ?int $userId): bool
    {
        if ($userId === null) {
            return false;
        }

        $statement = $this->db()->prepare('SELECT id FROM music_likes WHERE track_id = :track_id AND user_id = :user_id LIMIT 1');
        $statement->execute(['track_id' => $trackId, 'user_id' => $userId]);

        return (bool) $statement->fetchColumn();
    }

    public function toggleLike(int $trackId, int $userId): array
    {
        $this->db()->beginTransaction();

        try {
            if ($this->userLiked($trackId, $userId)) {
                $statement = $this->db()->prepare('DELETE FROM music_likes WHERE track_id = :track_id AND user_id = :user_id');
                $statement->execute(['track_id' => $trackId, 'user_id' => $userId]);
                $liked = false;
            } else {
                $statement = $this->db()->prepare(
                    'INSERT INTO music_likes (track_id, user_id, created_at)
                     VALUES (:track_id, :user_id, NOW())'
                );
                $statement->execute(['track_id' => $trackId, 'user_id' => $userId]);
                $liked = true;
            }

            $likeCount = $this->syncLikeCount($trackId);
            $this->db()->commit();

            return [
                'liked' => $liked,
                'like_count' => $likeCount,
            ];
        } catch (\Throwable $exception) {
            $this->db()->rollBack();
            throw $exception;
        }
    }

    private function playCount(int $trackId): int
    {
        $statement = $this->db()->prepare('SELECT play_count FROM music_tracks WHERE id = :id LIMIT 1');
        $statement->execute(['id' => $trackId]);

        return (int) $statement->fetchColumn();
    }

    private function syncLikeCount(int $trackId): int
    {
        $statement = $this->db()->prepare('SELECT COUNT(*) FROM music_likes WHERE track_id = :track_id');
        $statement->execute(['track_id' => $trackId]);
        $likeCount = (int) $statement->fetchColumn();

        $statement = $this->db()->prepare('UPDATE music_tracks SET like_count = :like_count WHERE id = :track_id');
        $statement->execute(['like_count' => $likeCount, 'track_id' => $trackId]);

        return $likeCount;
    }

    private function normalizeSort(string $sort): string
    {
        return match ($sort) {
            'populer', 'popular' => 'popular',
            'dinlenen', 'plays', 'listened', 'en-cok-dinlenen' => 'plays',
            'begenilen', 'liked' => 'liked',
            'one-cikan', 'featured' => 'featured',
            'premium' => 'premium',
            'ucretsiz', 'free' => 'free',
            default => 'newest',
        };
    }

    private function selectSql(): string
    {
        return "SELECT mt.*,
                c.name AS category_name,
                c.slug AS category_slug,
                a.artist_name AS linked_artist_name,
                a.slug AS linked_artist_slug,
                a.bio AS linked_artist_bio,
                a.avatar AS linked_artist_avatar,
                a.cover_image AS linked_artist_cover,
                a.verified AS linked_artist_verified,
                a.spotify_url AS linked_artist_spotify_url,
                a.youtube_url AS linked_artist_youtube_url,
                a.apple_music_url AS linked_artist_apple_music_url,
                u.username AS creator_username,
                u.role AS creator_role,
                COALESCE(up.display_name, pf.display_name, u.nickname, u.username, mt.artist_name, 'Artist') AS creator_display_name,
                COALESCE(up.avatar, pf.avatar_path) AS creator_avatar,
                COALESCE(pf.nickname, u.username) AS creator_slug,
                p.name AS package_name,
                g.genre_names,
                g.genre_slugs,
                g.primary_genre_name,
                g.primary_genre_slug
            FROM music_tracks mt
            LEFT JOIN categories c ON c.id = mt.category_id
            LEFT JOIN artists a ON a.id = mt.artist_id
            LEFT JOIN users u ON u.id = mt.user_id
            LEFT JOIN user_profiles up ON up.user_id = u.id
            LEFT JOIN profiles pf ON pf.user_id = u.id
            LEFT JOIN packages p ON p.id = mt.package_id
            LEFT JOIN (
                SELECT mtg.track_id,
                       GROUP_CONCAT(DISTINCT mg.name ORDER BY mg.sort_order ASC, mg.name ASC SEPARATOR ', ') AS genre_names,
                       GROUP_CONCAT(DISTINCT mg.slug ORDER BY mg.sort_order ASC, mg.slug ASC SEPARATOR ',') AS genre_slugs,
                       SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT mg.name ORDER BY mg.sort_order ASC, mg.name ASC SEPARATOR ','), ',', 1) AS primary_genre_name,
                       SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT mg.slug ORDER BY mg.sort_order ASC, mg.slug ASC SEPARATOR ','), ',', 1) AS primary_genre_slug
                FROM music_track_genres mtg
                INNER JOIN music_genres mg ON mg.id = mtg.genre_id
                GROUP BY mtg.track_id
            ) g ON g.track_id = mt.id";
    }

    private function normalize(array $track): array
    {
        $cover = (string) (($track['cover_image'] ?? '') ?: '/uploads/music-covers/track-1.svg');
        $audio = (string) (($track['audio_file'] ?? '') ?: '');
        $privacy = (string) (($track['privacy'] ?? '') ?: 'public');
        $isPremium = in_array($privacy, ['premium', 'subscriber', 'private'], true) || !empty($track['package_id']);
        $genreNames = (string) (($track['genre_names'] ?? '') ?: ($track['category_name'] ?? 'Music'));
        $genreSlugs = (string) (($track['genre_slugs'] ?? '') ?: ($track['category_slug'] ?? 'music'));

        $track['id'] = (int) ($track['id'] ?? 0);
        $track['user_id'] = isset($track['user_id']) && $track['user_id'] !== null ? (int) $track['user_id'] : null;
        $track['category_id'] = isset($track['category_id']) && $track['category_id'] !== null ? (int) $track['category_id'] : null;
        $track['package_id'] = isset($track['package_id']) && $track['package_id'] !== null ? (int) $track['package_id'] : null;
        $track['title'] = (string) (($track['title'] ?? '') ?: 'Untitled Track');
        $track['slug'] = (string) ($track['slug'] ?? '');
        $track['artist_name'] = (string) (($track['artist_name'] ?? '') ?: 'Zalorox Music');
        $track['artist'] = $track['artist_name'];
        if (!empty($track['linked_artist_name'])) {
            $track['artist_name'] = (string) $track['linked_artist_name'];
            $track['artist'] = $track['artist_name'];
        }
        $track['description'] = (string) (($track['description'] ?? '') ?: '');
        $track['cover_image'] = $cover;
        $track['cover'] = $cover;
        $track['audio_file'] = $audio;
        $track['audio'] = $audio;
        $track['external_link'] = (string) (($track['external_link'] ?? '') ?: '');
        $track['youtube_url'] = (string) (($track['youtube_url'] ?? '') ?: '');
        $track['spotify_url'] = (string) (($track['spotify_url'] ?? '') ?: '');
        $track['apple_music_url'] = (string) (($track['apple_music_url'] ?? '') ?: '');
        $track['privacy'] = $privacy;
        $track['status'] = (string) (($track['status'] ?? '') ?: 'published');
        $track['play_count'] = (int) ($track['play_count'] ?? 0);
        $track['view_count'] = (int) ($track['view_count'] ?? 0);
        $track['like_count'] = (int) ($track['like_count'] ?? 0);
        $track['plays'] = $track['play_count'];
        $track['likes'] = $track['like_count'];
        $track['featured'] = (int) ($track['featured'] ?? 0);
        $track['is_premium'] = $isPremium;
        $track['premium'] = $isPremium;
        $track['genre_names'] = $genreNames;
        $track['genre_slugs'] = $genreSlugs;
        $track['genre'] = (string) (($track['primary_genre_name'] ?? '') ?: strtok($genreNames, ',') ?: 'Music');
        $track['genre_slug'] = (string) (($track['primary_genre_slug'] ?? '') ?: strtok($genreSlugs, ',') ?: 'music');
        $track['category'] = (string) (($track['category_name'] ?? '') ?: $track['genre']);
        $track['creator_display_name'] = (string) (($track['creator_display_name'] ?? '') ?: $track['artist_name']);
        $track['creator_slug'] = (string) (($track['creator_slug'] ?? '') ?: 'creator');
        $track['creator_avatar'] = $track['creator_avatar'] ?? null;
        $track['package_name'] = $track['package_name'] ?? null;
        $track['artist_id'] = isset($track['artist_id']) && $track['artist_id'] !== null ? (int) $track['artist_id'] : null;
        $track['artist_slug'] = (string) (($track['linked_artist_slug'] ?? '') ?: $this->slugify((string) $track['artist_name']));
        $track['artist_avatar'] = (string) (($track['linked_artist_avatar'] ?? '') ?: $track['cover_image']);
        $track['artist_cover_image'] = (string) (($track['linked_artist_cover'] ?? '') ?: $track['cover_image']);
        $track['artist_verified'] = !empty($track['linked_artist_verified']);
        $track['spotify_url'] = (string) (($track['spotify_url'] ?? '') ?: ($track['linked_artist_spotify_url'] ?? ''));
        $track['youtube_url'] = (string) (($track['youtube_url'] ?? '') ?: ($track['linked_artist_youtube_url'] ?? ''));
        $track['apple_music_url'] = (string) (($track['apple_music_url'] ?? '') ?: ($track['linked_artist_apple_music_url'] ?? ''));

        return $track;
    }

    private function normalizeGenre(array $genre): array
    {
        return [
            'id' => (int) ($genre['id'] ?? 0),
            'name' => (string) (($genre['name'] ?? '') ?: 'Music'),
            'slug' => (string) (($genre['slug'] ?? '') ?: 'music'),
            'description' => (string) (($genre['description'] ?? '') ?: ''),
            'icon' => (string) (($genre['icon'] ?? '') ?: ''),
            'banner' => (string) (($genre['banner'] ?? '') ?: ''),
            'sort_order' => (int) ($genre['sort_order'] ?? 0),
            'track_count' => (int) ($genre['track_count'] ?? 0),
        ];
    }

    private function slugify(string $value): string
    {
        $value = strtolower(trim($value));
        $value = strtr($value, [
            'ç' => 'c', 'ğ' => 'g', 'ı' => 'i', 'ö' => 'o', 'ş' => 's', 'ü' => 'u',
            'Ç' => 'c', 'Ğ' => 'g', 'İ' => 'i', 'Ö' => 'o', 'Ş' => 's', 'Ü' => 'u',
        ]);
        $value = preg_replace('~[^a-z0-9]+~', '-', $value) ?: '';
        $value = trim($value, '-');

        return $value !== '' ? substr($value, 0, 160) : 'artist';
    }
}
