package com.cappielloantonio.tempo.widget;

import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;

import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
import com.cappielloantonio.tempo.R;

import androidx.media3.common.C;
import androidx.media3.session.MediaController;
import androidx.media3.session.SessionToken;

import com.cappielloantonio.tempo.service.MediaService;
import com.cappielloantonio.tempo.util.AssetLinkUtil;
import com.cappielloantonio.tempo.util.MusicUtil;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.concurrent.ExecutionException;

public final class WidgetUpdateManager {

    private static final int WIDGET_SAFE_ART_SIZE = 512;

    public static void updateFromState(Context ctx,
                                       String title,
                                       String artist,
                                       String album,
                                       Bitmap art,
                                       boolean playing,
                                       boolean shuffleEnabled,
                                       int repeatMode,
                                       long positionMs,
                                       long durationMs,
                                       String songLink,
                                       String albumLink,
                                       String artistLink) {
        if (TextUtils.isEmpty(title)) title = ctx.getString(R.string.widget_not_playing);
        if (TextUtils.isEmpty(artist)) artist = ctx.getString(R.string.widget_placeholder_subtitle);
        if (TextUtils.isEmpty(album)) album = "";

        final TimingInfo timing = createTimingInfo(positionMs, durationMs);

        AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
        int[] ids = mgr.getAppWidgetIds(new ComponentName(ctx, WidgetProvider4x1.class));
        for (int id : ids) {
            android.widget.RemoteViews rv = choosePopulate(ctx, title, artist, album, art, playing,
                    timing.elapsedText, timing.totalText, timing.progress, shuffleEnabled, repeatMode, id);
            WidgetProvider.attachIntents(ctx, rv, id, songLink, albumLink, artistLink);
            mgr.updateAppWidget(id, rv);
        }
    }

    public static void pushNow(Context ctx) {
        AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
        int[] ids = mgr.getAppWidgetIds(new ComponentName(ctx, WidgetProvider4x1.class));
        for (int id : ids) {
            android.widget.RemoteViews rv = chooseBuild(ctx, id);
            WidgetProvider.attachIntents(ctx, rv, id, null, null, null);
            mgr.updateAppWidget(id, rv);
        }
    }

    public static void updateFromState(Context ctx,
                                       String title,
                                       String artist,
                                       String album,
                                       String coverArtId,
                                       boolean playing,
                                       boolean shuffleEnabled,
                                       int repeatMode,
                                       long positionMs,
                                       long durationMs,
                                       String songLink,
                                       String albumLink,
                                       String artistLink) {
        final Context appCtx = ctx.getApplicationContext();
        final String t = TextUtils.isEmpty(title) ? appCtx.getString(R.string.widget_not_playing) : title;
        final String a = TextUtils.isEmpty(artist) ? appCtx.getString(R.string.widget_placeholder_subtitle) : artist;
        final String alb = !TextUtils.isEmpty(album) ? album : "";
        final boolean p = playing;
        final boolean sh = shuffleEnabled;
        final int rep = repeatMode;
        final TimingInfo timing = createTimingInfo(positionMs, durationMs);
        final String songLinkFinal = songLink;
        final String albumLinkFinal = albumLink;
        final String artistLinkFinal = artistLink;

        if (!TextUtils.isEmpty(coverArtId)) {
            CustomGlideRequest.loadAlbumArtBitmap(
                    appCtx,
                    coverArtId,
                    WIDGET_SAFE_ART_SIZE,
                    new CustomTarget<Bitmap>() {
                        @Override
                        public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
                            AppWidgetManager mgr = AppWidgetManager.getInstance(appCtx);
                            int[] ids = mgr.getAppWidgetIds(new ComponentName(appCtx, WidgetProvider4x1.class));
                            for (int id : ids) {
                                android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, alb, resource, p,
                                        timing.elapsedText, timing.totalText, timing.progress, sh, rep, id);
                                WidgetProvider.attachIntents(appCtx, rv, id, songLinkFinal, albumLinkFinal, artistLinkFinal);
                                mgr.updateAppWidget(id, rv);
                            }
                        }

                        @Override
                        public void onLoadCleared(Drawable placeholder) {
                            AppWidgetManager mgr = AppWidgetManager.getInstance(appCtx);
                            int[] ids = mgr.getAppWidgetIds(new ComponentName(appCtx, WidgetProvider4x1.class));
                            for (int id : ids) {
                                android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, alb, null, p,
                                        timing.elapsedText, timing.totalText, timing.progress, sh, rep, id);
                                WidgetProvider.attachIntents(appCtx, rv, id, songLinkFinal, albumLinkFinal, artistLinkFinal);
                                mgr.updateAppWidget(id, rv);
                            }
                        }
                    }
            );
        } else {
            AppWidgetManager mgr = AppWidgetManager.getInstance(appCtx);
            int[] ids = mgr.getAppWidgetIds(new ComponentName(appCtx, WidgetProvider4x1.class));
            for (int id : ids) {
                android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, alb, null, p,
                        timing.elapsedText, timing.totalText, timing.progress, sh, rep, id);
                WidgetProvider.attachIntents(appCtx, rv, id, songLinkFinal, albumLinkFinal, artistLinkFinal);
                mgr.updateAppWidget(id, rv);
            }
        }
    }

    public static void refreshFromController(Context ctx) {
        final Context appCtx = ctx.getApplicationContext();
        SessionToken token = new SessionToken(appCtx, new ComponentName(appCtx, MediaService.class));
        ListenableFuture<MediaController> future = new MediaController.Builder(appCtx, token).buildAsync();
        future.addListener(() -> {
            try {
                if (!future.isDone()) return;
                MediaController c = future.get();
                androidx.media3.common.MediaItem mi = c.getCurrentMediaItem();
                String title = null, artist = null, album = null, coverId = null;
                String songLink = null, albumLink = null, artistLink = null;
                if (mi != null && mi.mediaMetadata != null) {
                    if (mi.mediaMetadata.title != null) title = mi.mediaMetadata.title.toString();
                    if (mi.mediaMetadata.artist != null)
                        artist = mi.mediaMetadata.artist.toString();
                    if (mi.mediaMetadata.albumTitle != null)
                        album = mi.mediaMetadata.albumTitle.toString();
                    if (mi.mediaMetadata.extras != null) {
                        Bundle extras = mi.mediaMetadata.extras;
                        if (title == null) title = mi.mediaMetadata.extras.getString("title");
                        if (artist == null) artist = mi.mediaMetadata.extras.getString("artist");
                        if (album == null) album = mi.mediaMetadata.extras.getString("album");
                        coverId = extras.getString("coverArtId");

                        songLink = extras.getString("assetLinkSong");
                        if (songLink == null) {
                            songLink = AssetLinkUtil.buildLink(AssetLinkUtil.TYPE_SONG, extras.getString("id"));
                        }

                        albumLink = extras.getString("assetLinkAlbum");
                        if (albumLink == null) {
                            albumLink = AssetLinkUtil.buildLink(AssetLinkUtil.TYPE_ALBUM, extras.getString("albumId"));
                        }

                        artistLink = extras.getString("assetLinkArtist");
                        if (artistLink == null) {
                            artistLink = AssetLinkUtil.buildLink(AssetLinkUtil.TYPE_ARTIST, extras.getString("artistId"));
                        }
                    }
                }
                long position = c.getCurrentPosition();
                long duration = c.getDuration();
                if (position == C.TIME_UNSET) position = 0;
                if (duration == C.TIME_UNSET) duration = 0;
                updateFromState(appCtx,
                        title != null ? title : appCtx.getString(R.string.widget_not_playing),
                        artist != null ? artist : appCtx.getString(R.string.widget_placeholder_subtitle),
                        album,
                        coverId,
                        c.isPlaying(),
                        c.getShuffleModeEnabled(),
                        c.getRepeatMode(),
                        position,
                        duration,
                        songLink,
                        albumLink,
                        artistLink);
                c.release();
            } catch (ExecutionException | InterruptedException ignored) {
            }
        }, MoreExecutors.directExecutor());
    }

    private static TimingInfo createTimingInfo(long positionMs, long durationMs) {
        long safePosition = Math.max(0L, positionMs);
        long safeDuration = durationMs > 0 ? durationMs : 0L;
        if (safeDuration > 0 && safePosition > safeDuration) {
            safePosition = safeDuration;
        }

        String elapsed = (safeDuration > 0 || safePosition > 0)
                ? MusicUtil.getReadableDurationString(safePosition, true)
                : null;
        String total = safeDuration > 0
                ? MusicUtil.getReadableDurationString(safeDuration, true)
                : null;

        int progress = 0;
        if (safeDuration > 0) {
            long scaled = safePosition * WidgetViewsFactory.PROGRESS_MAX;
            long progressLong = scaled / safeDuration;
            if (progressLong < 0) {
                progress = 0;
            } else if (progressLong > WidgetViewsFactory.PROGRESS_MAX) {
                progress = WidgetViewsFactory.PROGRESS_MAX;
            } else {
                progress = (int) progressLong;
            }
        }

        return new TimingInfo(elapsed, total, progress);
    }

    public static android.widget.RemoteViews chooseBuild(Context ctx, int appWidgetId) {
        LayoutSize size = resolveLayoutSize(ctx, appWidgetId);
        switch (size) {
            case MEDIUM:
                return WidgetViewsFactory.buildMedium(ctx);
            case LARGE:
                return WidgetViewsFactory.buildLarge(ctx);
            case EXPANDED:
                return WidgetViewsFactory.buildExpanded(ctx);
            case COMPACT:
            default:
                return WidgetViewsFactory.buildCompact(ctx);
        }
    }

    private static android.widget.RemoteViews choosePopulate(Context ctx,
                                                             String title,
                                                             String artist,
                                                             String album,
                                                             Bitmap art,
                                                             boolean playing,
                                                             String elapsedText,
                                                             String totalText,
                                                             int progress,
                                                             boolean shuffleEnabled,
                                                             int repeatMode,
                                                             int appWidgetId) {
        LayoutSize size = resolveLayoutSize(ctx, appWidgetId);
        switch (size) {
            case MEDIUM:
                return WidgetViewsFactory.populateMedium(ctx, title, artist, album, art, playing,
                        elapsedText, totalText, progress, shuffleEnabled, repeatMode);
            case LARGE:
                return WidgetViewsFactory.populateLarge(ctx, title, artist, album, art, playing,
                        elapsedText, totalText, progress, shuffleEnabled, repeatMode);
            case EXPANDED:
                return WidgetViewsFactory.populateExpanded(ctx, title, artist, album, art, playing,
                        elapsedText, totalText, progress, shuffleEnabled, repeatMode);
            case COMPACT:
            default:
                return WidgetViewsFactory.populateCompact(ctx, title, artist, album, art, playing,
                        elapsedText, totalText, progress, shuffleEnabled, repeatMode);
        }
    }

    private static LayoutSize resolveLayoutSize(Context ctx, int appWidgetId) {
        AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
        android.os.Bundle opts = mgr.getAppWidgetOptions(appWidgetId);
        int minH = opts != null ? opts.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) : 0;
        int expandedThreshold = ctx.getResources().getInteger(R.integer.widget_expanded_min_height_dp);
        int largeThreshold = ctx.getResources().getInteger(R.integer.widget_large_min_height_dp);
        int mediumThreshold = ctx.getResources().getInteger(R.integer.widget_medium_min_height_dp);
        if (minH >= expandedThreshold) return LayoutSize.EXPANDED;
        if (minH >= largeThreshold) return LayoutSize.LARGE;
        if (minH >= mediumThreshold) return LayoutSize.MEDIUM;
        return LayoutSize.COMPACT;
    }

    private enum LayoutSize {
        COMPACT,
        MEDIUM,
        LARGE,
        EXPANDED
    }

    private static final class TimingInfo {
        final String elapsedText;
        final String totalText;
        final int progress;

        TimingInfo(String elapsedText, String totalText, int progress) {
            this.elapsedText = elapsedText;
            this.totalText = totalText;
            this.progress = progress;
        }
    }

}