package com.avg.zaap.crashlibrary;

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.IBinder;

import com.avg.zaap.crashlibrary.core.logger.CrashLogger;
import com.avg.zaap.crashlibrary.offline.IConnectivityHelper;
import com.avg.zaap.crashlibrary.offline.service.ICrashReportingServiceBroadcastReceiverCallback;
import com.avg.zaap.crashlibrary.offline.uploader.IOfflineUploader;

/**
 * This service runs in its own process which make is capable of withstanding an unrecoverable crash
 * in the main process and process exit.
 * <p/>
 * Created by marek.osvald on 31. 3. 2016.
 */
@SuppressLint("Registered")
public class CrashReportingService extends Service implements ICrashReportingServiceBroadcastReceiverCallback {

    private static final String TAG = CrashReportingService.class.getSimpleName();

    private ICrashServiceCommunicator.Stub mBinder;
    private ICrashReporter mCrashReporter;
    private IConnectivityHelper mConnectivityHelper;
    private IOfflineUploader mOfflineUploader;
    private ICrashReportingServiceFactory mFactory;

    /**
     * Default constructor. Uses the default dependency factory.
     */
    @SuppressWarnings("unused")
    public CrashReportingService() {
        this(new CrashReportingServiceFactory());
    }

    /**
     * Parametric constructor. Sets the dependency factory to be used.
     *
     * @param factory dependency factory to be used
     */
    public CrashReportingService(ICrashReportingServiceFactory factory) {
        mFactory = factory;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        CrashLogger.d(TAG, "onStartCommand() called, process ID: %d", android.os.Process.myPid());

        BroadcastReceiver broadcastReceiver = mFactory.getBroadcastReceiver(this);
        mConnectivityHelper = mFactory.getConnectivityHelper(this);
        mOfflineUploader = mFactory.getOfflineUploader(this);

        readConnectionState();
        registerReceiver(broadcastReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
        initializeCrashReporterIfNotAlready();
        return Service.START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        CrashLogger.d(TAG, "onBind() called");
        initializeCrashReporterIfNotAlready();
        mCrashReporter.startWatchingNativeCrashReports();
        return mBinder;
    }

    @Override
    public void onDestroy() {
        mCrashReporter.stopWatchingNativeCrashReports();
        super.onDestroy();
    }

    @Override
    public void onConnectionChange(ConnectionStatus connectionStatus) {
        CrashLogger.d(TAG, "onConnectionChange() called, connectionStatus: %s", connectionStatus);

        if (mConnectivityHelper.isConnectivitySuitable(connectionStatus)) {
            initializeOfflineUploader();
        } else {
            CrashLogger.d(TAG, "Connection unavailable, calling stopUploader().");
            mOfflineUploader.stopUploader();
        }
    }

    private void initializeCrashReporterIfNotAlready() {
        if (mCrashReporter == null) {
            mCrashReporter = mFactory.getCrashReporter(this);
        }

        mBinder = mFactory.getCrashServiceBinder(this, mCrashReporter);
    }

    private void readConnectionState() {
        final ConnectionStatus connectionStatus = mConnectivityHelper.getConnectionStatus();
        CrashLogger.d(TAG, "readConnectionState() called, connectionStatus: %s", connectionStatus);

        if (mConnectivityHelper.isConnectivitySuitable(connectionStatus)) {
            initializeOfflineUploader();
        }
    }

    private void initializeOfflineUploader() {
        CrashLogger.d(TAG, "New available connection detected, initializing offline crash uploader");
        mOfflineUploader.startUploader();
    }

}
