package org.altbeacon.bluetooth;

import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.HandlerThread;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import org.altbeacon.beacon.logging.LogManager;

/**
 * @hide
 * Internal library class.  Do not use directly.
 */
@SuppressWarnings("javadoc")
@RequiresApi(21)
public class BluetoothTestJob extends JobService {
    private static final String TAG = BluetoothTestJob.class.getSimpleName();
    @Nullable
    private Handler mHandler = null;
    @Nullable
    private HandlerThread mHandlerThread = null;
    private static int sOverrideJobId = -1;

    /**
     * Allows configuration of the job id for the Android Job Scheduler.  If not configured, this
     * will default to he value in the AndroidManifest.xml
     *
     * WARNING:  If using this library in a multi-process application, this method may not work.
     * This is considered a private API and may be removed at any time.
     *
     * the preferred way of setting this is in the AndroidManifest.xml as so:
     * <code>
     * <service android:name="org.altbeacon.bluetooth.BluetoothTestJob">
     *   <meta-data android:name="jobId" android:value="1001" tools:replace="android:value"/>
     * </service>
     * </code>
     *
     * @param id
     */
    public static void setOverrideJobId(int id) {
        sOverrideJobId = id;
    }

    /**
     * Returns the job id to be used to schedule this job.  This may be set in the
     * AndroidManifest.xml or in single process applications by using #setOverrideJobId
     * @param context
     * @return
     */
    public static int getJobId(Context context) {
        if (sOverrideJobId >= 0) {
            LogManager.i(TAG, "Using BluetoothTestJob JobId from static override: "+
                    sOverrideJobId);
            return sOverrideJobId;
        }
        PackageItemInfo info = null;
        try {
            info = context.getPackageManager().getServiceInfo(new ComponentName(context,
                    BluetoothTestJob.class), PackageManager.GET_META_DATA);
        } catch (PackageManager.NameNotFoundException e) { /* do nothing here */ }
        if (info != null && info.metaData != null && info.metaData.get("jobId") != null) {
            int jobId = info.metaData.getInt("jobId");
            LogManager.i(TAG, "Using BluetoothTestJob JobId from manifest: "+jobId);
            return jobId;
        }
        else {
            throw new RuntimeException("Cannot get job id from manifest.  " +
                    "Make sure that the BluetoothTestJob is configured in the manifest.");
        }
    }

    public BluetoothTestJob() {
    }

    public boolean onStartJob(final JobParameters params) {
        if(this.mHandlerThread == null) {
            this.mHandlerThread = new HandlerThread("BluetoothTestThread");
            this.mHandlerThread.start();
        }

        if(this.mHandler == null) {
            this.mHandler = new Handler(this.mHandlerThread.getLooper());
        }

        this.mHandler.post(new Runnable() {
            public void run() {
                boolean found = false;
                LogManager.i(BluetoothTestJob.TAG, "Bluetooth Test Job running");
                int testType = params.getExtras().getInt("test_type");
                if(testType == BluetoothMedic.NO_TEST) {
                    found = true;
                    LogManager.d(BluetoothTestJob.TAG, "No test specified.  Done with job.");
                }

                if((testType & BluetoothMedic.SCAN_TEST) == BluetoothMedic.SCAN_TEST) {
                    LogManager.d(BluetoothTestJob.TAG, "Scan test specified.");
                    found = true;
                    if (!BluetoothMedic.getInstance().runScanTest(BluetoothTestJob.this)) {
                        LogManager.d(TAG, "scan test failed");
                    }
                }

                if((testType & BluetoothMedic.TRANSMIT_TEST) == BluetoothMedic.TRANSMIT_TEST) {
                    if(found) {
                        try {
                            Thread.sleep(10000L);
                        } catch (InterruptedException e) {
                            /* do nothing */
                        }
                    }

                    LogManager.d(BluetoothTestJob.TAG, "Transmit test specified.");
                    found = true;
                    if (!BluetoothMedic.getInstance().runTransmitterTest(BluetoothTestJob.this)) {
                        LogManager.d(TAG, "transmit test failed");
                    }
                }

                if(!found) {
                    LogManager.w(BluetoothTestJob.TAG, "Unknown test type:" + testType + "  Exiting.");
                }

                BluetoothTestJob.this.jobFinished(params, false);
            }
        });
        return true;
    }

    public boolean onStopJob(JobParameters params) {
        return true;
    }
}
