package com.project.ilsaenterprise;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.hardware.fingerprint.FingerprintManager;
import android.location.Location;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;

import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.model.MapStyleOptions;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.project.ilsaenterprise.models.Attendance;
import com.project.ilsaenterprise.models.Employees;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polygon;
import com.google.android.gms.maps.model.PolygonOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class MapActivity extends FragmentActivity implements OnMapReadyCallback {

    private static final String TAG = "MapActivity";
    private static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
    private static final String COURSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1234;
    private static final int PLAY_SERVICE_RESOLUTION_REQUEST = 4799;
    private static final float DEFAULT_ZOOM = 16.5f;
    private static final int ERROR_DIALOG_REQUEST = 9001;
    //vars
    private Boolean mLocationPermissionsGranted = false;
    private GoogleMap mMap;
    CheckBox checkBox;
    SeekBar seekRed, seekGreen, seekBlue;
    Button btDraw;
    RelativeLayout btClear;
    FusedLocationProviderClient mFusedLocationProviderClient;
    FloatingActionButton onLocation;
    Location currentLocation;
    Employees employees;

    private FirebaseDatabase mFirebaseDatabase;
    private FirebaseAuth mAuth;
    private FirebaseAuth.AuthStateListener mAuthListener;

    DatabaseReference databaseReference;
    private static int UPDATE_INTERVAL = 5000;
    private static int FASTEST_INTERVAL = 3000;
    private static int DISPLACEMENT = 10;
    private MapView mapView;
    Boolean cek;

    Polygon polygon = null;
    ArrayList<String> latLngList = new ArrayList<>();
    List<Marker> markerList = new ArrayList<>();
    ArrayList<String> geoPosition = new ArrayList<>();

    private String currentDate = new SimpleDateFormat("dd MMMM yyyy", Locale.getDefault()).format(new Date());//Untuk Database jgn diganti format

    private TextView textView, txtInfo;
    private ImageView imageView;
    private FingerprintManager fingerprintManager;
    private FingerprintManager.AuthenticationCallback authenticationCallback;
    DatabaseReference historyRef;
    private Button startScanBtn;

    final String timeStamp = String.valueOf(System.currentTimeMillis());
    private String lat, lng;
    private BottomSheetDialog bottomSheetDialog;
    private  DatabaseReference checkAttendanceRef = FirebaseDatabase.getInstance().getReference().child("attendance").child(currentDate);
    private DatabaseReference userPhotoRef;
    Task location;
    private DatabaseReference checkAttendance;
    private GoogleSignInAccount googleLogin;
    private FirebaseAuth userAuth;
    private FirebaseUser userFirebase;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.Dark));
        setContentView(R.layout.activity_map);
        googleLogin = GoogleSignIn.getLastSignedInAccount(getApplicationContext());
        userAuth = FirebaseAuth.getInstance();
        userFirebase = userAuth.getCurrentUser();
        getLocationPermission();

        checkAtt();
        btDraw = findViewById(R.id.bt_draw);
        btClear = findViewById(R.id.bt_clear);
        userPhotoRef = FirebaseDatabase.getInstance().getReference().child("usersPhoto");
        checkAttendance = FirebaseDatabase.getInstance().getReference("attendanceWFH").child(currentDate);

        textView = findViewById(R.id.textScanner);
        bottomSheetDialog = new BottomSheetDialog(
                MapActivity.this, R.style.BottomSheetDialogTheme
        );

        employees = new Employees();
        btDraw.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkAttendance.addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot snapshot) {
                        if(snapshot.hasChild("Check In")){
                            if(snapshot.child("Check In").hasChild(userFirebase.getUid())){
                                Toast.makeText(getBaseContext(), "Anda sedang WFH", Toast.LENGTH_LONG).show();
                            }
                        }
                        else {
                            View bottomSheetView = LayoutInflater.from(getApplicationContext())
                                    .inflate(
                                            R.layout.layout_popup_fingerprint,
                                            (LinearLayout)findViewById(R.id.bottomSheetContainer)
                                    );
                            startScan();
                            fingerprintManager.authenticate(null, null, 0, authenticationCallback, null);
//                bottomSheetView.findViewById(R.id.buttonScanner).setOnClickListener(new View.OnClickListener() {
//                    @Override
//                    public void onClick(View v) {
//
//                    }
//                });
                            bottomSheetDialog.setContentView(bottomSheetView);
                            bottomSheetDialog.show();
                        }
                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError error) {

                    }
                });

//                Intent intent = new Intent(MapActivity.this, FingerAuth.class);
//                intent.putExtra("geoPosition", latLngList);
//                startActivity(intent);
//                finish();
//        Log.d(TAG, "Nama : " + userID);
//                    writeNewAdmin(user.getUid(), latitude, longitude);
            }
        });

        btClear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getLocationPermission();
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        if(isServicesOK()){
            initMap();
            getLocationPermission();
        }
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        startActivity(new Intent(MapActivity.this, Home.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK));
        finish();
    }

    @Override
    public void onDestroy()
    {
        Log.e(TAG, "onDestroy");
        super.onDestroy();
        currentLocation = null;
        mMap.clear();
        mMap.setLocationSource(null);
    }

    private void clockCheck()
    {
        Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    while (!isInterrupted()) {
                        Thread.sleep(1000);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                TextView thour = findViewById(R.id.textHour);
                                long date = System.currentTimeMillis();
                                SimpleDateFormat adf = new SimpleDateFormat("kk : mm : ss");
                                String hourString = adf.format(date);
                                thour.setText(hourString);
                            }
                        });
                    }
                } catch (InterruptedException e) {

                }
            }
        };
        t.start();
    }

    private void checkAtt()
    {
        //final FirebaseUser user = mAuth.getInstance().getCurrentUser();
        final String userID = userFirebase.getUid();
        final TextView checkUser = (TextView) findViewById(R.id.checkKehadiran);
        final TextView textIO = findViewById(R.id.textInOut);
        cek = false;
        checkAttendanceRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                //long count= dataSnapshot.getChildrenCount();
                if(!dataSnapshot.child("Check In").hasChild(userID)){
                    checkUser.setText("Belum Tapping");
                    textIO.setText("Jam Masuk");
                    btDraw.setText("Check In");
                    btDraw.setEnabled(true);
                    clockCheck();
                    cek = false;
                }
                else if(!dataSnapshot.child("Check Out").hasChild(userID)){
                    checkUser.setText("Sedang Bekerja");
                    textIO.setText("Jam Keluar");
                    btDraw.setText("Check Out");
                    clockCheck();
                    cek = false;
                }
                else{
                    checkUser.setText("Absensi Selesai");
                    textIO.setText("Durasi Kerja Hari ini");
                    btDraw.setText("Terima Kasih");
                    startTime();
                    checkUser.setTextColor(getResources().getColor(R.color.Yellow));
                    cek = true;
                    btDraw.setEnabled(false);
                    btClear.setEnabled(false);
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }
        });
    }

    private void startTime(){
        //final FirebaseUser user = mAuth.getInstance().getCurrentUser();
        final String userID = userFirebase.getUid();

        checkAttendanceRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                Attendance history = dataSnapshot.child("Check In").child(userID).getValue(Attendance.class);
                Attendance history2 = dataSnapshot.child("Check Out").child(userID).getValue(Attendance.class);
                String firstTime = getTime(Long.parseLong(history.getTime()));
                String endtime = getTime(Long.parseLong(history2.getTime()));

                SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
                Date start, end;
                try{
                    start = format.parse(firstTime);
                    end = format.parse(endtime);

                    long diff = end.getTime() - start.getTime();

                    long diffSeconds = diff / 1000 % 60;
                    long diffMinutes = diff / (60 * 1000) % 60;
                    long diffHour = diff / (60 * 60 * 1000) % 24;

                    TextView totalWork = findViewById(R.id.textHour);
                    totalWork.setTextSize(20);
                    totalWork.setText(diffHour + " Jam " + diffMinutes + " Menit " + diffSeconds + " Detik");

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

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });
    }

    private String getTime(long time) {
        Calendar cal = Calendar.getInstance(Locale.ENGLISH);
        cal.setTimeInMillis(time);
        String date = DateFormat.format("HH:mm:ss", cal).toString();
        return date;
    }

    private void moveCamera(LatLng latLng, float zoom){
        Log.d(TAG, "moveCamera: moving the camera to: lat: " + latLng.latitude + ", lng: " + latLng.longitude );

        //LatLng markerLoc = new LatLng(latLng.latitude, latLng.longitude);
        mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoom));
        mMap.clear();
    }

    public boolean isServicesOK(){

        int available = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(MapActivity.this);

        if(available == ConnectionResult.SUCCESS){
            return true;
        }
        else if(GoogleApiAvailability.getInstance().isUserResolvableError(available)){
            Dialog dialog = GoogleApiAvailability.getInstance().getErrorDialog(MapActivity.this, available, ERROR_DIALOG_REQUEST);
            dialog.show();
        }else{
//            Toast.makeText(this, "You can't make map requests", Toast.LENGTH_SHORT).show();
        }
        return false;
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        mMap.isIndoorEnabled();

        try {
            boolean success = googleMap.setMapStyle(MapStyleOptions.loadRawResourceStyle(this, R.raw.new_map));
            if(!success){
                return;
            }
        }catch (Resources.NotFoundException e){
            Log.e(TAG, "Error", e);
        }

        if (mLocationPermissionsGranted) {
            getDeviceLocation();

            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }

            mMap.setMyLocationEnabled(true);
            mMap.getUiSettings().setMyLocationButtonEnabled(false);
        }
    }

    public boolean pointInPolygon(LatLng point) {
        // ray casting alogrithm http://rosettacode.org/wiki/Ray-casting_algorithm
        PolygonOptions recOptions = new PolygonOptions().add(
                        new LatLng(3.580267, 98.678713),
                        new LatLng(3.579716, 98.679239),
                        new LatLng(3.580605, 98.680253),
                        new LatLng(3.581103, 98.679679),
                        new LatLng(3.580267, 98.678713));

        polygon = mMap.addPolygon(recOptions);
        polygon.setFillColor(0x7F00FF00);

        int crossings = 0;
        List<LatLng> path = polygon.getPoints();
        path.remove(path.size()-1); //remove the last point that is added automatically by getPoints()

        // for each edge
        for (int i=0; i < path.size(); i++) {
            LatLng a = path.get(i);
            int j = i + 1;
            //to close the last edge, you have to take the first point of your polygon
            if (j >= path.size()) {
                j = 0;
            }
            LatLng b = path.get(j);
            if (rayCrossesSegment(point, a, b)) {
                crossings++;
            }
        }
        // odd number of crossings?
        return (crossings % 2 == 1);
    }

    public boolean rayCrossesSegment(LatLng point, LatLng a, LatLng b) {
        // Ray Casting algorithm checks, for each segment, if the point is 1) to the left of the segment and 2) not above nor below the segment. If these two conditions are met, it returns true
        double px = point.longitude,
                py = point.latitude,
                ax = a.longitude,
                ay = a.latitude,
                bx = b.longitude,
                by = b.latitude;
        if (ay > by) {
            ax = b.longitude;
            ay = b.latitude;
            bx = a.longitude;
            by = a.latitude;
        }
        // alter longitude to cater for 180 degree crossings
        if (px < 0 || ax <0 || bx <0) { px += 360; ax+=360; bx+=360; }
        // if the point has the same latitude as a or b, increase slightly py
        if (py == ay || py == by) py += 0.00000001;


        // if the point is above, below or to the right of the segment, it returns false
        if ((py > by || py < ay) || (px > Math.max(ax, bx))){
            return false;
        }
        // if the point is not above, below or to the right and is to the left, return true
        else if (px < Math.min(ax, bx)){
            return true;
        }
        // if the two above conditions are not met, you have to compare the slope of segment [a,b] (the red one here) and segment [a,p] (the blue one here) to see if your point is to the left of segment [a,b] or not
        else {
            double red = (ax != bx) ? ((by - ay) / (bx - ax)) : Double.POSITIVE_INFINITY;
            double blue = (ax != px) ? ((py - ay) / (px - ax)) : Double.POSITIVE_INFINITY;
            return (blue >= red);
        }

    }

    private void getDeviceLocation(){
        mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
        try{
            if(mLocationPermissionsGranted){
                //&& task.getResult() != null
                location = mFusedLocationProviderClient.getLastLocation();
                location.addOnCompleteListener(new OnCompleteListener() {
                    @SuppressLint("SetTextI18n")
                    @Override
                    public void onComplete(@NonNull Task task) {
                        if(task.isSuccessful() && task.getResult() != null){
                            currentLocation = (Location) task.getResult();

                            moveCamera(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()), DEFAULT_ZOOM);
                            MarkerOptions marker = new MarkerOptions().position(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()));
                            //mMap.addMarker(marker);

                            boolean isPoint = pointInPolygon(new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude()));
                            databaseReference = FirebaseDatabase.getInstance().getReference("kebun");

                            String newLat = String.valueOf(currentLocation.getLatitude());
                            String newLng = String.valueOf(currentLocation.getLongitude());
                            latLngList.add(newLat);
                            latLngList.add(newLng);

                            if(isPoint && cek != true){
                                btDraw.setText("Check In");
                                btDraw.setEnabled(true);
                                Toast.makeText(MapActivity.this, "Anda didalam lokasi", Toast.LENGTH_SHORT).show();
                            }
                            else if(!isPoint && cek != true){
                                btDraw.setText("Tidak dilokasi");
                                btDraw.setEnabled(true);
                            }
                            else if(cek == true){
                                btDraw.setEnabled(false);
                            }
                        } else{
                            Toast.makeText(MapActivity.this, "Pencarian Titik Gagal", Toast.LENGTH_SHORT).show();
                            mFusedLocationProviderClient.getLastLocation();
                        }
                    }
                });
            }
        }catch (SecurityException e){
            Log.e(TAG, "getDeviceLocation: SecurityException: " + e.getMessage() );
        }
    }

    private void initMap(){
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapView);

        assert mapFragment != null;
        mapFragment.getMapAsync(MapActivity.this);
    }

    private void getLocationPermission(){
        String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION};

        if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
                FINE_LOCATION) == PackageManager.PERMISSION_GRANTED){
            if(ContextCompat.checkSelfPermission(this.getApplicationContext(),
                    COURSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
            {
                mLocationPermissionsGranted = true;
                initMap();
            }else{
                ActivityCompat.requestPermissions(this,
                        permissions,
                        LOCATION_PERMISSION_REQUEST_CODE);
            }
        }else{
            ActivityCompat.requestPermissions(this,
                    permissions,
                    LOCATION_PERMISSION_REQUEST_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        mLocationPermissionsGranted = false;

        if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0) {
                for (int grantResult : grantResults) {
                    if (grantResult != PackageManager.PERMISSION_GRANTED) {
                        mLocationPermissionsGranted = false;
                        return;
                    }
                }
                mLocationPermissionsGranted = true;
                //initialize our map
                initMap();
            }
        }
    }

    private void startScan(){
        fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);

        authenticationCallback = new FingerprintManager.AuthenticationCallback() {
            @Override
            public void onAuthenticationError(int errorCode, CharSequence errString) {
                //textView.setText("Error");
                //Toast.makeText(MapActivity.this, "Otentikasi Error", Toast.LENGTH_LONG).show();
//                imageView.setImageResource(R.drawable.image2);
                super.onAuthenticationError(errorCode, errString);
            }

            @Override
            public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
                //textView.setText("Help");
//                imageView.setImageResource(R.drawable.image1);
                super.onAuthenticationHelp(helpCode, helpString);
            }
            //private String currentDate = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(new Date());
            //
            @Override
            public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);
//                textView.setText( "Otentikasi Berhasil");
//                imageView.setImageResource(R.drawable.image3);

                //FirebaseUser user = mAuth.getInstance().getCurrentUser();
                final String userID = userFirebase.getUid();

                final String currentDate = new SimpleDateFormat("dd MMMM yyyy", Locale.getDefault()).format(new Date());

                databaseReference = FirebaseDatabase.getInstance().getReference("attendance");
                historyRef = FirebaseDatabase.getInstance().getReference("history");

                databaseReference.child(currentDate).addListenerForSingleValueEvent(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                        if(!dataSnapshot.child("Check In").hasChild(userID)){
                            Attendance attendance = new Attendance(userID, timeStamp, "Masuk", "-", latLngList.get(0), latLngList.get(1));
                            databaseReference.child(currentDate).child("Check In").child(userID).setValue(attendance);
                            historyRef.child(userID).child(timeStamp).setValue(attendance);
                        }
                        else if (!dataSnapshot.child("Check Out").hasChild(userID)){
                            Attendance attendance = new Attendance(userID, timeStamp, "Keluar", "-", latLngList.get(0), latLngList.get(1));
                            databaseReference.child(currentDate).child("Check Out").child(userID).setValue(attendance);
                            historyRef.child(userID).child(timeStamp).setValue(attendance);
                        }
                    }
                    @Override
                    public void onCancelled(@NonNull DatabaseError databaseError) {

                    }
                });


                bottomSheetDialog.dismiss();
                Toast.makeText(MapActivity.this, "Otentikasi Berhasil", Toast.LENGTH_LONG).show();
                Intent intent = new Intent(MapActivity.this, HistoryAttendance.class);
                startActivity(intent);
                finish();
            }

            @Override
            public void onAuthenticationFailed() {
                Toast.makeText(MapActivity.this, "Otentikasi Gagal", Toast.LENGTH_LONG).show();
                super.onAuthenticationFailed();
            }
        };
    }

    public void scannerButton(View view){

    }
}
