package com.nadi.player.nativeplayer.tracks;

import android.content.Context;

import androidx.media3.common.C;
import androidx.media3.common.Player;
import androidx.media3.common.TrackGroup;
import androidx.media3.common.TrackSelectionOverride;
import androidx.media3.common.TrackSelectionParameters;
import androidx.media3.common.Tracks;
import androidx.media3.common.util.UnstableApi;

import java.util.ArrayList;
import java.util.List;

/**
 * Tiny helper that surfaces the currently available audio and subtitle
 * tracks to a host-friendly format and applies the user's pick via the
 * Player's {@link TrackSelectionParameters}.
 *
 * Why not {@code TrackSelectionDialogBuilder}? It works fine with the
 * default Media3 ExoPlayer but pulls in a Material-Components dialog
 * theme that fights with our flat dark / gold palette. Rolling a 30-line
 * helper + an AlertDialog keeps the visual language consistent and adds
 * no new dependencies.
 *
 * For text/subtitle tracks we also expose an "Off" entry which maps to
 * disabling the entire {@link C#TRACK_TYPE_TEXT} group via
 * {@code setTrackTypeDisabled}.
 */
@UnstableApi
public final class TrackSelectorHelper {

    public static final class Option {
        public final String label;
        public final TrackGroup group;
        public final int trackIndex;
        public final boolean selected;
        public final boolean off;   // "Disable subtitles" pseudo-entry

        private Option(String label, TrackGroup group, int trackIndex,
                       boolean selected, boolean off) {
            this.label = label;
            this.group = group;
            this.trackIndex = trackIndex;
            this.selected = selected;
            this.off = off;
        }

        static Option track(String label, TrackGroup g, int i, boolean sel) {
            return new Option(label, g, i, sel, false);
        }
        static Option off(boolean sel) {
            return new Option("Off", null, -1, sel, true);
        }
    }

    private TrackSelectorHelper() {}

    /** @param trackType one of {@link C#TRACK_TYPE_AUDIO} / {@link C#TRACK_TYPE_TEXT}. */
    public static List<Option> listTracks(Player player, int trackType) {
        List<Option> out = new ArrayList<>();
        if (player == null) return out;

        Tracks tracks;
        try { tracks = player.getCurrentTracks(); }
        catch (Throwable t) { return out; }

        boolean textDisabled = trackType == C.TRACK_TYPE_TEXT
                && player.getTrackSelectionParameters().disabledTrackTypes
                        .contains(C.TRACK_TYPE_TEXT);

        if (trackType == C.TRACK_TYPE_TEXT) {
            out.add(Option.off(textDisabled));
        }

        for (Tracks.Group tg : tracks.getGroups()) {
            if (tg.getType() != trackType) continue;
            TrackGroup group = tg.getMediaTrackGroup();
            for (int i = 0; i < group.length; i++) {
                if (!tg.isTrackSupported(i)) continue;
                String label = labelFor(group, i, trackType, out.size());
                boolean sel = tg.isTrackSelected(i) && !textDisabled;
                out.add(Option.track(label, group, i, sel));
            }
        }
        return out;
    }

    public static void apply(Player player, int trackType, Option choice) {
        if (player == null || choice == null) return;
        TrackSelectionParameters.Builder b =
                player.getTrackSelectionParameters().buildUpon();

        if (trackType == C.TRACK_TYPE_TEXT) {
            // "Off" → disable text type entirely; otherwise re-enable +
            // pin the chosen track.
            b.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, choice.off);
        }

        // Clear any prior override on this track type, then add ours.
        b.clearOverridesOfType(trackType);
        if (!choice.off && choice.group != null && choice.trackIndex >= 0) {
            b.addOverride(new TrackSelectionOverride(choice.group, choice.trackIndex));
        }
        player.setTrackSelectionParameters(b.build());
    }

    private static String labelFor(TrackGroup g, int i, int type, int idx) {
        androidx.media3.common.Format f = g.getFormat(i);
        StringBuilder sb = new StringBuilder();
        if (f.language != null && !f.language.isEmpty() && !"und".equals(f.language)) {
            sb.append(displayLang(f.language));
        }
        if (f.label != null && !f.label.isEmpty()) {
            if (sb.length() > 0) sb.append(" · ");
            sb.append(f.label);
        }
        if (type == C.TRACK_TYPE_AUDIO && f.channelCount > 0) {
            if (sb.length() > 0) sb.append(" · ");
            sb.append(channelLabel(f.channelCount));
        }
        if (sb.length() == 0) {
            sb.append(type == C.TRACK_TYPE_AUDIO ? "Audio " : "Subtitle ")
              .append(idx + 1);
        }
        return sb.toString();
    }

    private static String displayLang(String code) {
        try {
            java.util.Locale loc = new java.util.Locale(code);
            String name = loc.getDisplayLanguage(java.util.Locale.getDefault());
            return name == null || name.isEmpty() ? code : name;
        } catch (Throwable t) {
            return code;
        }
    }

    private static String channelLabel(int n) {
        switch (n) {
            case 1: return "Mono";
            case 2: return "Stereo";
            case 6: return "5.1";
            case 8: return "7.1";
            default: return n + "ch";
        }
    }

    /** Show a plain AlertDialog with the given options. */
    public static void prompt(Context ctx, String title, List<Option> opts,
                              OnPick onPick) {
        if (opts == null || opts.isEmpty()) {
            new android.app.AlertDialog.Builder(ctx)
                    .setTitle(title)
                    .setMessage("No tracks available.")
                    .setPositiveButton(android.R.string.ok, null)
                    .show();
            return;
        }
        String[] labels = new String[opts.size()];
        int checked = -1;
        for (int i = 0; i < opts.size(); i++) {
            labels[i] = opts.get(i).label;
            if (opts.get(i).selected) checked = i;
        }
        final int[] chosen = { checked };
        new android.app.AlertDialog.Builder(ctx)
                .setTitle(title)
                .setSingleChoiceItems(labels, checked, (d, w) -> chosen[0] = w)
                .setPositiveButton("Apply", (d, w) -> {
                    if (chosen[0] >= 0 && chosen[0] < opts.size() && onPick != null) {
                        onPick.onPicked(opts.get(chosen[0]));
                    }
                })
                .setNegativeButton(android.R.string.cancel, null)
                .show();
    }

    public interface OnPick {
        void onPicked(Option opt);
    }
}
