package edu.whs.spin2018.baoapp.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;

import java.net.URISyntaxException;
import java.util.HashSet;

import io.socket.emitter.Emitter;

public class BaoService extends Service implements BaoServiceInterface {

    public static final String TAG = "BAOSERVICE";
    private static final String KANAL_ID = "edu.whs.spin2018.baoapp";
    private static final String KANAL_NAME = "BaoMainService";
    private final IBinder lBinder = new LocalBinder();
    private ClientSocket cs;

    private String uuid;
    private String benutzername;
    private HashSet<String> aktuelleRaeume;

    private Handler sHandler;

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

    @Override
    public void onCreate() {
        super.onCreate();
        aktuelleRaeume = new HashSet<>();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            starteEigenenVordergrundService();
        } else {
            startForeground(1, erstelleBenachrichtigung());
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            cs = new ClientSocket(Konstanten.URL);

        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        this.benutzername = intent.getStringExtra(Konstanten.EXTRA_BENUTZERNAME);
        this.uuid = intent.getStringExtra(Konstanten.EXTRA_UUID);
        verbinden(benutzername, uuid);

        sHandler = new Handler();
        sHandler.postAtTime(this::sendeHeartbeat, SystemClock.uptimeMillis() + 30 * 1000);

        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * Sendet in einem bestimmten Zeitintervall ein Signal zum Server um diesem zu zeigen, dass der
     * Client noch aktiv ist.
     */
    private void sendeHeartbeat() {
        sendeNachricht("Heartbeat", "Heartbeat", uuid);
        sHandler.postAtTime(this::sendeHeartbeat, SystemClock.uptimeMillis() + 30 * 1000);
        Looper.loop();
    }

    @Override
    public void verbinden(String benutzername, String uuid) {
        cs.setVerbundenListener(os -> {
            /*
             * Wenn der Socket verbunden ist, muss innerhalb eines serverseitigen Zeitfensters,
             * ein Login erfolgen, damit die Verbindung vom Server nicht verworfen wird.
             */
            login(benutzername, uuid);

        });
        cs.verbinden();

    }


    /**
     * Sendet ein Login - Event mit den Benutzerdaten zum Server.
     *
     * @param benutzername - Benutzername
     * @param uuid         - UUID des Benutzers
     */
    private void login(String benutzername, String uuid) {
        cs.login(benutzername, uuid, Konstanten.APP_NAME, Konstanten.APP_VERSION);
    }

    @Override
    public void trennen() {
        cs.trennen();
    }

    @Override
    public void raumBetreten(String raum) {
        aktuelleRaeume.add(raum);
        cs.raumBetreten(raum);
    }

    @Override
    public void raumVerlassen(String raum) {
        aktuelleRaeume.remove(raum);
        cs.raumVerlassen(raum);
    }

    @Override
    public void zeigeBenutzerImRaum(String raum) {
        cs.zeigeBenutzerImRaum(raum);
    }

    @Override
    public void sendeNachricht(String inhalt, String typ, String empfaengerUUID) {
        cs.sendeNachricht(inhalt, typ, empfaengerUUID);
    }

    @Override
    public void sendeBroadcast(String inhalt, String typ, String raum) {
        cs.sendeBroadcast(inhalt, typ, raum);
    }


    public void registriereNachrichtenListener(Emitter.Listener listener) {
        cs.setNachrichtenListener(listener);
    }

    @Override
    public void registriereBenutzerVerlaesstRaumListener(Emitter.Listener listener) {
        cs.setBenutzerVerlaesstRaumListener(listener);
    }

    @Override
    public void registriereBenutzerTrittRaumBeiListener(Emitter.Listener listener) {
        cs.setBenutzerBetrittRaumListener(listener);
    }

    @Override
    public void registriereVerbundenListener(Emitter.Listener listener) {
        cs.setVerbundenListener(listener);
    }

    @Override
    public void registriereBenutzerListeErhaltenListener(Emitter.Listener listener) {
        cs.setZeigeBenutzerImRaumListener(listener);
    }

    @Override
    public void entferneListener(String event, Emitter.Listener listener) {
        cs.entferneListener(event, listener);
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void starteEigenenVordergrundService() {
        NotificationChannel kanal = new NotificationChannel(KANAL_ID, KANAL_NAME, NotificationManager.IMPORTANCE_LOW);
        kanal.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(kanal);

        startForeground(1, erstelleBenachrichtigung());
    }

    private Notification erstelleBenachrichtigung() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,
                KANAL_ID);

        return builder.setOngoing(true)
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .setCategory(Notification.CATEGORY_SERVICE).build();
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        cs.trennen();
        stopSelf();
        stopForeground(true);
    }

    public class LocalBinder extends Binder {
        public BaoService getService() {
            return BaoService.this;
        }
    }
}
