package com.izouma.screen_stream_plugin;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.text.format.DateUtils;

import net.gotev.uploadservice.MultipartUploadRequest;
import net.gotev.uploadservice.ServerResponse;
import net.gotev.uploadservice.UploadInfo;
import net.gotev.uploadservice.UploadNotificationConfig;
import net.gotev.uploadservice.UploadStatusDelegate;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.Map;

import static android.os.Build.VERSION_CODES.O;
import static net.gotev.uploadservice.Placeholders.ELAPSED_TIME;
import static net.gotev.uploadservice.Placeholders.PROGRESS;
import static net.gotev.uploadservice.Placeholders.TOTAL_FILES;
import static net.gotev.uploadservice.Placeholders.UPLOADED_FILES;
import static net.gotev.uploadservice.Placeholders.UPLOAD_RATE;

public class VideoProcessService extends Service implements ImageAvailableListener.OnMatchedListener {
    private static final String TAG             = "VideoProcessService";
    private static final int    MSG_START       = 0x111;
    private static final int    MSG_STOP        = 0x112;
    private static final String CHANNEL_ID      = "Recording";
    private static final String CHANNEL_NAME    = "Screen Recorder Notifications";
    private final static int    NOTIFICATION_ID = android.os.Process.myPid();

    private int                    playerInfoId;
    private MediaProjection        mediaProjection;
    private ImageReader            imageReader;
    private ImageAvailableListener imageAvailableListener;
    private VirtualDisplay         virtualDisplay;
    private Handler                mHandler;
    private boolean                running;
    private Map<String, String>    result;
    private NotificationManager    notificationManager;
    private Notification.Builder   notificationBuilder;
    private long                   mLastFiredTime = 0;
    private long                   startTimeMs;
    private long                   startTime;

    @Override
    public void onCreate() {
        super.onCreate();
        if (Build.VERSION.SDK_INT >= O) {
            createNotificationChannel();
        }
        startForeground(NOTIFICATION_ID, getBuilder().build());
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                mHandler = new Handler(msg -> {
                    if (MSG_START == msg.what) {
                        if (!running) {
                            startTime = System.currentTimeMillis();
                            imageAvailableListener = new ImageAvailableListener(VideoProcessService.this);
                            imageAvailableListener.setOnMatchedListener(VideoProcessService.this);
                            imageReader = ImageReader.newInstance(1280, 720, PixelFormat.RGBA_8888, 2);
                            imageReader.setOnImageAvailableListener(imageAvailableListener, mHandler);
                            virtualDisplay = mediaProjection.createVirtualDisplay(TAG + "-display",
                                    1280, 720, 1, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
                                    imageReader.getSurface(), null, null);
                            running = true;
                            startTimeMs = System.currentTimeMillis();
                        }
                        return false;
                    } else if (MSG_STOP == msg.what) {
                        releaseResources();
                        clearNotification();
                        running = false;
                        SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences(getApplicationContext().getPackageName(), MODE_PRIVATE);
                        String jsonStr = sharedPreferences.getString("video", "{}");
                        try {
                            JSONObject jsonObject = new JSONObject(jsonStr);
                            jsonObject.put(String.valueOf(playerInfoId), imageAvailableListener.getVideoPath());
                            sharedPreferences.edit().putString("video", jsonObject.toString()).apply();
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        try {
                            String uploadId = new MultipartUploadRequest(VideoProcessService.this, "http://202.79.174.56:8206/playerInfo/uploadVideo")
                                    .addFileToUpload(imageAvailableListener.getVideoPath(), "video")
                                    // .addFileToUpload("/storage/emulated/0/Android/data/com.izouma.mobilecybergames/files/record/record1553655902913.flv", "video")
                                    .addParameter("id", String.valueOf(playerInfoId))
                                    .setNotificationConfig(getNotificationConfig())
                                    .setMaxRetries(3)
                                    .setDelegate(new UploadStatusDelegate() {
                                        @Override
                                        public void onProgress(Context context, UploadInfo uploadInfo) {

                                        }

                                        @Override
                                        public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, Exception exception) {
                                            System.out.println("upload error");
                                        }

                                        @Override
                                        public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {

                                        }

                                        @Override
                                        public void onCancelled(Context context, UploadInfo uploadInfo) {

                                        }
                                    })
                                    .startUpload();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    return true;
                });
                Looper.loop();
            }
        }.start();
    }

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

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

    @Override
    public void onProgress() {
        updateNotification(System.currentTimeMillis() - startTimeMs);
    }

    @Override
    public void onMatched(Map<String, String> result) {
        this.result = result;
        releaseResources();
    }

    private void releaseResources() {
        mediaProjection.stop();
        imageReader.setOnImageAvailableListener(null, mHandler);
        virtualDisplay.release();
        imageAvailableListener.release();
    }

    @TargetApi(O)
    private void createNotificationChannel() {
        NotificationChannel channel =
                new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
        channel.setShowBadge(false);
        getNotificationManager().createNotificationChannel(channel);
    }

    NotificationManager getNotificationManager() {
        if (notificationManager == null) {
            notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        }
        return notificationManager;
    }

    private Notification.Builder getBuilder() {
        if (notificationBuilder == null) {
            Notification.Builder builder = new Notification.Builder(this)
                    .setContentTitle("正在录制游戏")
                    .setOngoing(true)
                    .setLocalOnly(true)
                    .setOnlyAlertOnce(true)
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(getApplicationContext().getResources().getIdentifier("ic_launcher", "mipmap", getApplicationContext().getPackageName()));
            if (Build.VERSION.SDK_INT >= O) {
                builder.setChannelId(CHANNEL_ID)
                        .setUsesChronometer(true);
            }
            notificationBuilder = builder;
        }
        return notificationBuilder;
    }

    public void updateNotification(long timeMs) {
        if (SystemClock.elapsedRealtime() - mLastFiredTime < 1000) {
            return;
        }
        Notification notification = getBuilder()
                .setContentText("已录制: " + DateUtils.formatElapsedTime(timeMs / 1000))
                .build();
        getNotificationManager().notify(NOTIFICATION_ID, notification);
        mLastFiredTime = SystemClock.elapsedRealtime();
    }

    public void clearNotification() {
        mLastFiredTime = 0;
        getNotificationManager().cancelAll();
    }

    class VideoProcessBinder extends Binder {
        void start(MediaProjection m, int id) {
            playerInfoId = id;
            mediaProjection = m;
            result = null;
            Message msg = mHandler.obtainMessage(MSG_START);
            mHandler.sendMessage(msg);
        }

        void stop() {
            Message msg = mHandler.obtainMessage(MSG_STOP);
            mHandler.sendMessage(msg);
        }
    }

    protected UploadNotificationConfig getNotificationConfig() {
        UploadNotificationConfig config = new UploadNotificationConfig();
        Intent intent = new Intent();
        intent.setPackage(getApplicationContext().getPackageName());
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        PendingIntent clickIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        config.setTitleForAllStatuses("上传游戏结果")
                .setRingToneEnabled(true)
                .setClickIntentForAllStatuses(clickIntent)
                .setClearOnActionForAllStatuses(true);
        int icLauncher = getApplicationContext().getResources().getIdentifier("ic_launcher", "mipmap", getApplicationContext().getPackageName());
        config.getProgress().message = "Uploaded " + UPLOADED_FILES + " of " + TOTAL_FILES
                + " at " + UPLOAD_RATE + " - " + PROGRESS;
        config.getProgress().iconResourceID = icLauncher;
        config.getProgress().iconColorResourceID = Color.BLUE;

        config.getCompleted().message = "Upload completed successfully in " + ELAPSED_TIME;
        config.getCompleted().iconResourceID = icLauncher;
        config.getCompleted().iconColorResourceID = Color.GREEN;

        config.getError().message = "Error while uploading";
        config.getError().iconResourceID = icLauncher;
        config.getError().iconColorResourceID = Color.RED;

        config.getCancelled().message = "Upload has been cancelled";
        config.getCancelled().iconResourceID = icLauncher;
        config.getCancelled().iconColorResourceID = Color.YELLOW;

        return config;
    }
}
