package com.ms_square.android.design.overlay.service;

import android.annotation.TargetApi;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;

import com.ms_square.android.design.overlay.R;
import com.ms_square.android.design.overlay.activity.SettingsActivity;
import com.ms_square.android.design.overlay.app.AppEnvironment;
import com.ms_square.android.design.overlay.util.PrefUtil;
import com.ms_square.android.design.overlay.view.GridView;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import timber.log.Timber;

public class DesignOverlayService extends Service {

    private static final int NOTIFICATION_ID = 10000;

    private static final String ACTION_DISMISS = "com.ms_square.android.design.overlay.ACTION_DISMISS";

    private WindowManager mWindowManager;

    private NotificationManager mNotificationManager;

    private View mRootView;

    private ImageView mDesignImgView;

    private GridView mGridView;

    public static Intent createIntent(Context context) {
        return new Intent(context, DesignOverlayService.class);
    }

    @Override
    public void onCreate() {
        super.onCreate();

        AppEnvironment.INSTANCE.setOverlayServiceRunning(true);

        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

        showOverlay();

        registerReceiver(mReceiver, new IntentFilter(ACTION_DISMISS));

        PrefUtil.registerOnSharedPreferenceChangeListener(this, mPrefListener);

        showNotification();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return Service.START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        AppEnvironment.INSTANCE.setOverlayServiceRunning(false);
        PrefUtil.unregisterOnSharedPreferenceChangeListener(this, mPrefListener);
        unregisterReceiver(mReceiver);
        dismissOverlay();
        cancelNotification();
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void showOverlay() {
        mRootView = LayoutInflater.from(this).inflate(R.layout.service_design_overlay, null, false);
        mDesignImgView = (ImageView) mRootView.findViewById(R.id.design_image_view);
        mGridView = (GridView) mRootView.findViewById(R.id.grid_view);
        updateImageVisibility();
        updateImageAlpha();
        updateImage();
        updateGridSize();
        updateGridColor();
        updateGridVisibility();
        mWindowManager.addView(mRootView, createDefaultSystemWindowParams(PrefUtil.isFullScreen(this)));
    }

    private void dismissOverlay() {
        mWindowManager.removeView(mRootView);
        mRootView = null;
        mDesignImgView = null;
        mGridView = null;
    }

    private void updateImage() {
        if (mDesignImgView != null) {
            final Uri uri = PrefUtil.getDesignImageUri(this);
            if (uri != null) {
                new AsyncTask<Uri, Void, Bitmap>() {
                    @Override
                    protected Bitmap doInBackground(Uri... params) {
                        Bitmap bitmap = null;
                        InputStream stream = null;
                        try {
                            stream = getContentResolver().openInputStream(params[0]);
                            bitmap = BitmapFactory.decodeStream(stream);
                        } catch (FileNotFoundException fe) {
                            Timber.w("File was not found: %s", fe.toString());
                        } catch (SecurityException se) {
                            Timber.w("No longer have access permission to the uri: %s", se.toString());
                            // clear stored image Uri
                            PrefUtil.setDesignImageUri(getApplicationContext(), null);
                        } finally {
                            try {
                                if (stream != null) {
                                    stream.close();
                                }
                            } catch (IOException ignore) {}
                        }
                        return bitmap;
                    }

                    @Override
                    protected void onPostExecute(Bitmap bitmap) {
                        if (mDesignImgView != null) {
                            mDesignImgView.setImageBitmap(bitmap);
                        }
                    }
                }.execute(uri);
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void updateImageAlpha() {
        if (mDesignImgView != null) {
            final int alpha = PrefUtil.getDesignImageAlpha(this); // 0 - 255
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                mDesignImgView.setImageAlpha(alpha);
            } else {
                mDesignImgView.setAlpha(alpha);
            }
        }
    }

    private void updateImageVisibility() {
        if (mDesignImgView != null) {
            mDesignImgView.setVisibility(PrefUtil.isDesignImageEnabled(DesignOverlayService.this) ?
                    View.VISIBLE : View.INVISIBLE);
        }
    }

    private void updateGridSize() {
        if (mGridView != null) {
            final int gridSize = PrefUtil.getGridSize(DesignOverlayService.this);
            final boolean alignRight = PrefUtil.isAlignRight(DesignOverlayService.this);
            final boolean alignBottom = PrefUtil.isAlignBottom(DesignOverlayService.this);
            mGridView.updateGridSize(gridSize, alignRight, alignBottom);
        }
    }

    private void updateGridColor() {
        if (mGridView != null) {
            mGridView.updateGridColor(PrefUtil.getGridColor(DesignOverlayService.this));
        }
    }

    private void updateGridVisibility() {
        if (mGridView != null) {
            mGridView.setVisibility(PrefUtil.isGridEnabled(DesignOverlayService.this) ?
                    View.VISIBLE : View.INVISIBLE);
        }
    }

    private void showNotification() {
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(getString(R.string.notification_big_text)))
                .setSmallIcon(R.drawable.ic_notification)
                .setOngoing(true)
                .setContentTitle(getString(R.string.notification_title))
                .setContentText(getString(R.string.notification_small_text))
                .setContentIntent(getNotificationIntent(null));

        mBuilder.addAction(R.drawable.ic_action_clear, getString(R.string.notification_action_dismiss),
                getNotificationIntent(ACTION_DISMISS));

        // show the notification
        startForeground(NOTIFICATION_ID, mBuilder.build());
    }

    private void cancelNotification() {
        mNotificationManager.cancel(NOTIFICATION_ID);
    }

    private PendingIntent getNotificationIntent(String action) {
        if (action == null) {
            Intent intent = SettingsActivity.createIntent(this);
            return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        } else {
            Intent intent = new Intent(action);
            return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        }
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            switch (action) {
                case ACTION_DISMISS:
                    stopSelf();
                    break;
            }
        }
    };

    private final SharedPreferences.OnSharedPreferenceChangeListener mPrefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            switch (key) {
                case PrefUtil.PREF_FULLSCREEN: {
                    dismissOverlay();
                    showOverlay();
                    break;
                }
                case PrefUtil.PREF_DESIGN_IMAGE_ENABLED: {
                    updateImageVisibility();
                    break;
                }
                case PrefUtil.PREF_DESIGN_IMAGE_URI: {
                    updateImage();
                    break;
                }
                case PrefUtil.PREF_DESIGN_IMAGE_ALPHA: {
                    updateImageAlpha();
                    break;
                }
                case PrefUtil.PREF_GRID_ENABLED: {
                    updateGridVisibility();
                    break;
                }
                case PrefUtil.PREF_GRID_SIZE: {
                    updateGridSize();
                    break;
                }
                case PrefUtil.PREF_ALIGN_RIGHT: {
                    updateGridSize();
                    break;
                }
                case PrefUtil.PREF_ALIGN_BOTTOM: {
                    updateGridSize();
                    break;
                }
                case PrefUtil.PREF_GRID_COLOR: {
                    updateGridColor();
                    break;
                }
            }
        }
    };

    private static WindowManager.LayoutParams createDefaultSystemWindowParams(boolean isFullScreen) {
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                isFullScreen ? WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN : 0,
                PixelFormat.TRANSLUCENT);
        params.format = PixelFormat.RGBA_8888;
        return params;
    }
}