package de.danoeh.antennapod.ui.widget;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.RemoteViews;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;

import de.danoeh.antennapod.ui.appstartintent.MediaButtonStarter;
import de.danoeh.antennapod.ui.common.Converter;
import de.danoeh.antennapod.storage.preferences.UserPreferences;

import java.util.concurrent.TimeUnit;

import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.playback.base.PlayerStatus;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.ui.appstartintent.PlaybackSpeedActivityStarter;
import de.danoeh.antennapod.ui.appstartintent.VideoPlayerActivityStarter;
import de.danoeh.antennapod.ui.episodes.ImageResourceUtils;
import de.danoeh.antennapod.ui.episodes.TimeSpeedConverter;
import de.danoeh.antennapod.ui.glide.FastBlurTransformation;

/**
 * Updates the state of the player widget.
 */
public abstract class WidgetUpdater {
    private static final String TAG = "WidgetUpdater";

    public static class WidgetState {
        final Playable media;
        final PlayerStatus status;
        final int position;
        final int duration;
        final float playbackSpeed;

        public WidgetState(Playable media, PlayerStatus status, int position, int duration, float playbackSpeed) {
            this.media = media;
            this.status = status;
            this.position = position;
            this.duration = duration;
            this.playbackSpeed = playbackSpeed;
        }

        public WidgetState(PlayerStatus status) {
            this(null, status, Playable.INVALID_TIME, Playable.INVALID_TIME, 1.0f);
        }
    }

    /**
     * Update the widgets with the given parameters. Must be called in a background thread.
     */
    public static void updateWidget(Context context, WidgetState widgetState) {
        if (!PlayerWidget.isEnabled(context) || widgetState == null) {
            return;
        }

        PendingIntent startMediaPlayer;
        if (widgetState.media != null && widgetState.media.getMediaType() == MediaType.VIDEO) {
            startMediaPlayer = new VideoPlayerActivityStarter(context).getPendingIntent();
        } else {
            startMediaPlayer = new MainActivityStarter(context)
                    .withOpenPlayer().withClearBackStack().getPendingIntent();
        }

        PendingIntent startPlaybackSpeedDialog = new PlaybackSpeedActivityStarter(context).getPendingIntent();

        RemoteViews views;
        views = new RemoteViews(context.getPackageName(), R.layout.player_widget);

        if (widgetState.media != null) {
            views.setOnClickPendingIntent(R.id.layout_left, startMediaPlayer);
            views.setOnClickPendingIntent(R.id.imgvCover, startMediaPlayer);
            views.setOnClickPendingIntent(R.id.butPlaybackSpeed, startPlaybackSpeedDialog);

            views.setTextViewText(R.id.txtvTitle, widgetState.media.getEpisodeTitle());
            views.setViewVisibility(R.id.txtvTitle, View.VISIBLE);
            views.setViewVisibility(R.id.txtNoPlaying, View.GONE);

            String progressString = getProgressString(widgetState.position,
                    widgetState.duration, widgetState.playbackSpeed);
            if (progressString != null) {
                views.setViewVisibility(R.id.txtvProgress, View.VISIBLE);
                views.setTextViewText(R.id.txtvProgress, progressString);
            }

            if (widgetState.status == PlayerStatus.PLAYING) {
                views.setImageViewResource(R.id.butPlay, R.drawable.ic_widget_pause);
                views.setContentDescription(R.id.butPlay, context.getString(R.string.pause_label));
                views.setImageViewResource(R.id.butPlayExtended, R.drawable.ic_widget_pause);
                views.setContentDescription(R.id.butPlayExtended, context.getString(R.string.pause_label));
            } else {
                views.setImageViewResource(R.id.butPlay, R.drawable.ic_widget_play);
                views.setContentDescription(R.id.butPlay, context.getString(R.string.play_label));
                views.setImageViewResource(R.id.butPlayExtended, R.drawable.ic_widget_play);
                views.setContentDescription(R.id.butPlayExtended, context.getString(R.string.play_label));
            }
            views.setOnClickPendingIntent(R.id.butPlay,
                    MediaButtonStarter.createPendingIntent(context, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
            views.setOnClickPendingIntent(R.id.butPlayExtended,
                    MediaButtonStarter.createPendingIntent(context, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
            views.setOnClickPendingIntent(R.id.butRew,
                    MediaButtonStarter.createPendingIntent(context, KeyEvent.KEYCODE_MEDIA_REWIND));
            views.setOnClickPendingIntent(R.id.butFastForward,
                    MediaButtonStarter.createPendingIntent(context, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD));
            views.setOnClickPendingIntent(R.id.butSkip,
                    MediaButtonStarter.createPendingIntent(context, KeyEvent.KEYCODE_MEDIA_NEXT));
        } else {
            // start the app if they click anything
            views.setOnClickPendingIntent(R.id.layout_left, startMediaPlayer);
            views.setOnClickPendingIntent(R.id.butPlay, startMediaPlayer);
            views.setOnClickPendingIntent(R.id.butPlayExtended,
                    MediaButtonStarter.createPendingIntent(context, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
            views.setViewVisibility(R.id.txtvProgress, View.GONE);
            views.setViewVisibility(R.id.txtvTitle, View.GONE);
            views.setViewVisibility(R.id.txtNoPlaying, View.VISIBLE);
            views.setImageViewResource(R.id.imgvCover, R.mipmap.ic_launcher);
            views.setImageViewResource(R.id.butPlay, R.drawable.ic_widget_play);
            views.setImageViewResource(R.id.butPlayExtended, R.drawable.ic_widget_play);
        }

        ComponentName playerWidget = new ComponentName(context, PlayerWidget.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        int[] widgetIds = manager.getAppWidgetIds(playerWidget);

        for (int id : widgetIds) {
            Bundle options = manager.getAppWidgetOptions(id);
            SharedPreferences prefs = context.getSharedPreferences(PlayerWidget.PREFS_NAME, Context.MODE_PRIVATE);
            int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
            int columns = getCellsForSize(minWidth);
            if (columns < 3) {
                views.setViewVisibility(R.id.layout_center, View.INVISIBLE);
            } else {
                views.setViewVisibility(R.id.layout_center, View.VISIBLE);
            }
            boolean showPlaybackSpeed = prefs.getBoolean(PlayerWidget.KEY_WIDGET_PLAYBACK_SPEED + id, false);
            boolean showRewind = prefs.getBoolean(PlayerWidget.KEY_WIDGET_REWIND + id, false);
            boolean showFastForward = prefs.getBoolean(PlayerWidget.KEY_WIDGET_FAST_FORWARD + id, false);
            boolean showSkip = prefs.getBoolean(PlayerWidget.KEY_WIDGET_SKIP + id, false);
            boolean showCoverAsBcg = prefs.getBoolean(PlayerWidget.KEY_WIDGET_COVER_BACKGROUND + id, false);

            if (showPlaybackSpeed || showRewind || showSkip || showFastForward) {
                views.setInt(R.id.extendedButtonsContainer, "setVisibility", View.VISIBLE);
                views.setInt(R.id.butPlay, "setVisibility", View.GONE);
                views.setInt(R.id.butPlaybackSpeed, "setVisibility", showPlaybackSpeed ? View.VISIBLE : View.GONE);
                views.setInt(R.id.butRew, "setVisibility", showRewind ? View.VISIBLE : View.GONE);
                views.setInt(R.id.butFastForward, "setVisibility", showFastForward ? View.VISIBLE : View.GONE);
                views.setInt(R.id.butSkip, "setVisibility", showSkip ? View.VISIBLE : View.GONE);
            } else {
                views.setInt(R.id.extendedButtonsContainer, "setVisibility", View.GONE);
                views.setInt(R.id.butPlay, "setVisibility", View.VISIBLE);
            }

            if (showCoverAsBcg) {
                views.setViewVisibility(R.id.imgvCover, View.GONE);
                views.setViewVisibility(R.id.imgvBackground, View.VISIBLE);
                int iconSize = 4 * context.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
                Bitmap icon = null;
                if (widgetState.media != null) {
                    icon = loadCover(context, iconSize, widgetState.media, new FastBlurTransformation());
                }
                if (icon != null) {
                    views.setImageViewBitmap(R.id.imgvBackground, icon);
                } else {
                    views.setViewVisibility(R.id.imgvBackground, View.GONE);
                }
            } else {
                views.setViewVisibility(R.id.imgvCover, View.VISIBLE);
                views.setViewVisibility(R.id.imgvBackground, View.GONE);
                int iconSize = context.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
                int radius = context.getResources().getDimensionPixelSize(R.dimen.widget_inner_radius);
                Bitmap icon = null;
                if (widgetState.media != null) {
                    icon = loadCover(context, iconSize, widgetState.media, new RoundedCorners(radius));
                }
                if (icon != null) {
                    views.setImageViewBitmap(R.id.imgvCover, icon);
                } else {
                    views.setImageViewResource(R.id.imgvCover, R.mipmap.ic_launcher);
                }
            }
            int backgroundColor = prefs.getInt(PlayerWidget.KEY_WIDGET_COLOR + id, PlayerWidget.DEFAULT_COLOR);
            views.setInt(R.id.widgetLayout, "setBackgroundColor", backgroundColor);

            manager.updateAppWidget(id, views);
        }
    }

    private static Bitmap loadCover(Context context, int iconSize, Playable media, Transformation<Bitmap> transform) {
        try {
            return Glide.with(context)
                    .asBitmap()
                    .load(media.getImageLocation())
                    .dontAnimate()
                    .transform(transform)
                    .submit(iconSize, iconSize)
                    .get(500, TimeUnit.MILLISECONDS);
        } catch (Throwable tr1) {
            try {
                return Glide.with(context)
                        .asBitmap()
                        .load(ImageResourceUtils.getFallbackImageLocation(media))
                        .dontAnimate()
                        .transform(transform)
                        .submit(iconSize, iconSize)
                        .get(500, TimeUnit.MILLISECONDS);
            } catch (Throwable tr2) {
                Log.e(TAG, "Error loading the media icon for the widget", tr2);
                return null;
            }
        }
    }

    /**
     * Returns number of cells needed for given size of the widget.
     *
     * @param size Widget size in dp.
     * @return Size in number of cells.
     */
    private static int getCellsForSize(int size) {
        int n = 2;
        while (70 * n - 30 < size) {
            ++n;
        }
        return n - 1;
    }

    private static String getProgressString(int position, int duration, float speed) {
        if (position < 0 || duration <= 0) {
            return null;
        }
        TimeSpeedConverter converter = new TimeSpeedConverter(speed);
        if (UserPreferences.shouldShowRemainingTime()) {
            return Converter.getDurationStringLong(converter.convert(position)) + " / -"
                    + Converter.getDurationStringLong(converter.convert(Math.max(0, duration - position)));
        } else {
            return Converter.getDurationStringLong(converter.convert(position)) + " / "
                    + Converter.getDurationStringLong(converter.convert(duration));
        }
    }
}
