package com.seatel.mobilehall.ui.home.activity;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.seatel.mobilehall.R;
import com.seatel.mobilehall.data.prefs.LanguagePreference;
import com.seatel.mobilehall.ui.base.activity.BaseActivity;
import com.seatel.mobilehall.ui.home.adapter.ShopLocationAdapter;
import com.seatel.mobilehall.ui.home.interactor.LocationShopMapInteractor;
import com.seatel.mobilehall.ui.home.model.SeatelShopLocationModel;
import com.seatel.mobilehall.ui.home.model.ShopLocation;
import com.seatel.mobilehall.util.Constant;
import com.seatel.mobilehall.util.LocationRequestController;
import com.seatel.mobilehall.util.PermissionUtil;
import com.seatel.mobilehall.util.SeatelUtils;
import com.seatel.mobilehall.util.customview.CustomEditText;
import com.seatel.mobilehall.util.customview.ErrorHandleView;
import com.seatel.mobilehall.util.request.GetShopLocationRequest;
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.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.gson.Gson;
import com.google.maps.android.clustering.Cluster;
import com.google.maps.android.clustering.ClusterItem;
import com.google.maps.android.clustering.ClusterManager;
import com.google.maps.android.clustering.view.DefaultClusterRenderer;

import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;


public class LocationShopMapActivity extends BaseActivity implements OnMapReadyCallback,
        ClusterManager.OnClusterClickListener<ShopLocation>,
        ClusterManager.OnClusterInfoWindowClickListener<ShopLocation>,
        ClusterManager.OnClusterItemClickListener<ShopLocation>,
        ClusterManager.OnClusterItemInfoWindowClickListener<ShopLocation>, LocationShopMapInteractor, LocationRequestController.LocationUpdaterInterface {

    private ActionBar mActionBarMap;
    private GoogleMap mMap;
    private androidx.appcompat.widget.Toolbar toolbarMap;
    private final ArrayList<SeatelShopLocationModel> shopLocationSearchOrigin = new ArrayList<>();
    private final ArrayList<SeatelShopLocationModel> shopLocationSearchData = new ArrayList<>();
    private final ArrayList<SeatelShopLocationModel> shopLocationSearchAddress = new ArrayList<>();
    private ShopLocationAdapter shopLocationAdapter;
    private BottomSheetBehavior bottomSheetBehavior;
    private RelativeLayout rlBottomSheetSearch;
    private ClusterManager<ShopLocation> mClusterManager;
    private PermissionUtil.PermissionRequestObject mPhoneNumberRequest;
    private Location currentLocation = null;
    private ErrorHandleView errorHandleView;
    private Timer timer;
    private String searchText;
    private CustomEditText cetSearchBox;
    private String phoneForCall = "";
    private String languageQuery = "en";
    private int heightBottomSheetOrigin = 0;
    private boolean isSelectSearch = false;
    private LocationRequestController locationRequestController;
    private final float mapZoom = 12.5f;
    private int mOffset = 0;
    private int mLimiteTotal = 99;
    private int mLimite = 0;
    private String requestStr;

    @Override
    public boolean onClusterClick(Cluster<ShopLocation> cluster) {
        // Show a toast with some info when the cluster is clicked.
        String firstName = cluster.getItems().iterator().next().name;
        Toast.makeText(this, cluster.getSize() + " (including " + firstName + ")", Toast.LENGTH_SHORT).show();

        // Zoom in the cluster. Need to create LatLngBounds and including all the cluster items
        // inside of bounds, then animate to center of the bounds.

        // Create the builder to collect all essential cluster items for the bounds.
        LatLngBounds.Builder builder = LatLngBounds.builder();
        for (ClusterItem item : cluster.getItems()) {
            builder.include(item.getPosition());
        }
        // Get the LatLngBounds
        final LatLngBounds bounds = builder.build();

        // Animate camera to the bounds
        try {
            mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }

    @Override
    public void onClusterInfoWindowClick(Cluster<ShopLocation> cluster) {
        // Does nothing, but you could go to a list of the users.
    }

    @Override
    public boolean onClusterItemClick(ShopLocation item) {
        // Does nothing, but you could go into the user's profile page, for example.
        SeatelShopLocationModel model = new SeatelShopLocationModel(item.getId(), item.getName(),
                item.getAddress(), item.getContactNumber(), item.getHoursWork(), item.getLatitude(), item.getLongitude(), item.getLocalArea());
        ContactUsActivity.Companion.lunch(this, new Gson().toJson(model));
        return false;
    }

    @Override
    public void onClusterItemInfoWindowClick(ShopLocation item) {
        // Does nothing, but you could go into the user's profile page, for example.
    }

    @Override
    public void onLoadData(ArrayList<SeatelShopLocationModel> data) {
        if (data.size() > 98) {
            if (shopLocationSearchOrigin.size() < mLimiteTotal)
                shopLocationSearchOrigin.addAll(data);
            shopLocationSearchData.addAll(data);
            mOffset += mLimite;
            startRequestLocaiton("?limit=" + mLimite + "&offset=" + mOffset + requestStr);
        } else {
            String str = cetSearchBox.getText().toString();
            if (shopLocationSearchOrigin.size() < mLimiteTotal)
                shopLocationSearchOrigin.addAll(data);
            if (!str.isEmpty()) {
                shopLocationSearchData.clear();
                shopLocationAdapter.removeAll();
            }
            shopLocationSearchData.addAll(data);
            shopLocationAdapter.updatedDataLocation(shopLocationSearchData, false);
            addPinAddress();
            errorHandleView.setVisibility(View.GONE);
            isSelectSearch = false;
            if (shopLocationSearchAddress.isEmpty())
                keepShopLocationAdress(shopLocationSearchOrigin);
        }
    }

    private void keepShopLocationAdress(ArrayList<SeatelShopLocationModel> data) {
        for (SeatelShopLocationModel item : data) {
            if (!TextUtils.isEmpty(item.getLocalArea())) {
                shopLocationSearchAddress.add(item);
            }
        }
    }

    private void filterNameAdress(String strSearch) {
        if (mClusterManager != null) {
            mClusterManager.clearItems();
            mClusterManager.cluster();
        }
        shopLocationSearchAddress.clear();
        for (SeatelShopLocationModel item : shopLocationSearchOrigin) {
            if (item.getLocalArea().toLowerCase().contains(strSearch.toLowerCase())) {
                if (checkIsNotExisting(item.getLocalArea()))
                    shopLocationSearchAddress.add(item);
            }
        }
        shopLocationAdapter.removeAll();
        if (TextUtils.isEmpty(strSearch)) {
            shopLocationAdapter.updatedDataLocation(shopLocationSearchOrigin, false);
            addPinAddress();
        } else {
            shopLocationAdapter.updatedDataLocation(shopLocationSearchAddress, true);
        }
    }

    private boolean checkIsNotExisting(String location) {
        for (SeatelShopLocationModel item : shopLocationSearchAddress) {
            if (TextUtils.equals(item.getLocalArea().toLowerCase(), location.toLowerCase())) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void onStartSearch(@NotNull String str) {
        mOffset = 0;
        mLimite = 0;
        isSelectSearch = true;
        cetSearchBox.setText(str);
        getTotalShopFirst("&lang=" + languageQuery + "&list=mobile&searchByLocation=" + str + "&ehub=true");
    }

    @SuppressLint("MissingPermission")
    @Override
    public void onLocationCallBack(Object type, Location location) {
        currentLocation = location;
        if (mMap != null) mMap.setMyLocationEnabled(true);
        moveCameraCurrentLocaiton();
        locationRequestController.removeLocationUpdate();
    }


    /**
     * Draws profile photos inside markers (using IconGenerator).
     * When there are multiple people in the cluster, draw multiple photos (using MultiDrawable).
     */
    private class OwnIconRendered extends DefaultClusterRenderer<ShopLocation> {

        public OwnIconRendered(Context context, GoogleMap map, ClusterManager<ShopLocation> clusterManager) {
            super(context, map, clusterManager);
        }

        @Override
        protected void onBeforeClusterItemRendered(ShopLocation item, MarkerOptions markerOptions) {
            markerOptions.icon(BitmapDescriptorFactory.fromResource(item.iconPin)).title("");
            super.onBeforeClusterItemRendered(item, markerOptions);
        }
    }

    private void startShowMap() {
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(11.562108, 104.888535), mapZoom));

        mClusterManager = new ClusterManager<>(this, mMap);
        mClusterManager.setRenderer(new OwnIconRendered(getApplicationContext(), mMap, mClusterManager));
        mMap.setOnCameraIdleListener(mClusterManager);
        mMap.setOnMarkerClickListener(mClusterManager);
        mMap.setOnInfoWindowClickListener(mClusterManager);
        mClusterManager.setOnClusterClickListener(this);
        mClusterManager.setOnClusterInfoWindowClickListener(this);
        mClusterManager.setOnClusterItemClickListener(this);
        mClusterManager.setOnClusterItemInfoWindowClickListener(this);
        addPinAddress();
    }

    private void addPinAddress() {
        if (mClusterManager != null) {
            mClusterManager.clearItems();
            int total = shopLocationSearchData.size();
            for (int i = 0; i < total; i++) {
                SeatelShopLocationModel data = shopLocationSearchData.get(i);
                mClusterManager.addItem(new ShopLocation(data.getName(), R.drawable.ic_map_pin_white_bg,
                        new LatLng(data.getLatitude(), data.getLongitude()), data.getAddress(),
                        data.getContactNumber(), data.getHoursWork(), data.getId(), data.getLatitude(),
                        data.getLongitude(), data.getLocalArea()));
            }
            mClusterManager.cluster();
        }
    }

    private void getTotalShopFirst(final String queryStr) {
        requestStr = queryStr;
        errorHandleView.setViewMode(ErrorHandleView.Mode.LOADING);
        GetShopLocationRequest requestLocation = new GetShopLocationRequest(this);
        requestLocation.setOnErrorListener(new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                mLimite = 99;
                startRequestLocaiton("?limit=" + mLimite + "&offset=" + mOffset + queryStr);
            }
        });
        requestLocation.setStrQuery("?limit=" + mLimite + "&offset=" + mOffset + queryStr);
        requestLocation.execute(new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                if (response == null) return;
                mLimite = 99;
                if (response.has("metadata")) {
                    mLimiteTotal = response.optJSONObject("metadata").optInt("total");
                    if (mLimiteTotal < mLimite)
                        mLimite = mLimiteTotal;
                }
                startRequestLocaiton("?limit=" + mLimite + "&offset=" + mOffset + queryStr);
            }
        });
    }

    private void startRequestLocaiton(String queryStr) {
//        errorHandleView.setViewMode(ErrorHandleView.Mode.LOADING);
        GetShopLocationRequest requestLocation = new GetShopLocationRequest(this);
        requestLocation.setOnSuccess(this);
        requestLocation.setOnErrorListener(new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                isSelectSearch = false;
                errorHandleView.setVisibility(View.GONE);
            }
        });
        requestLocation.setStrQuery(queryStr);
        requestLocation.execute();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activityEnterRightAnimation();
        setContentView(R.layout.activity_shop_locations);

        moveToDefaultAfterDeniedPermission();

        locationRequestController = new LocationRequestController(this);
        locationRequestController.setLocationUpdateListener(this);
        locationRequestController.checkPermissions();

        errorHandleView = findViewById(R.id.error_view);
        languageQuery = LanguagePreference.Companion.getInstance(this).getAppSharedLanguageCodePreference().toLowerCase();

//        startRequestLocaiton("?lang=" + languageQuery + "&list=mobile");
        getTotalShopFirst("&lang=" + languageQuery + "&list=mobile&ehub=true");

        toolbarMap = findViewById(R.id.toolbarMap);
        setupToolbar();

        rlBottomSheetSearch = findViewById(R.id.bottom_sheet_search_map);
        bottomSheetBehavior = BottomSheetBehavior.from(rlBottomSheetSearch);
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);

        final RecyclerView recyclerViewBrand = findViewById(R.id.recycler_view_shop_search);
        recyclerViewBrand.setLayoutManager(new LinearLayoutManager(this));
        shopLocationAdapter = new ShopLocationAdapter(shopLocationSearchData, this);
        shopLocationAdapter.setClickLocalAreaSearch(this);
        recyclerViewBrand.setAdapter(shopLocationAdapter);
        setUpMap();

        final View rootView = getWindow().getDecorView().getRootView();
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect rect = new Rect();
                rootView.getWindowVisibleDisplayFrame(rect);

                int screenHeight = rootView.getHeight();
                int keyboardHeight = screenHeight - (rect.bottom - rect.top);
                if (keyboardHeight > screenHeight / 3) {
                    rlBottomSheetSearch.animate().translationY((float) -(keyboardHeight / 4)).setDuration(200);
                } else {
                    rlBottomSheetSearch.animate().translationY(0f).setDuration(200);
                    clearKeyBoard(false);
                }
            }
        });

        final RelativeLayout layoutSearch = findViewById(R.id.layout_view_search);
        layoutSearch.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                layoutSearch.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                View hidden = layoutSearch.getChildAt(3);
                View hidden2 = rlBottomSheetSearch.getChildAt(2);
                heightBottomSheetOrigin = hidden.getTop() + hidden2.getTop() + 20;
                bottomSheetBehavior.setPeekHeight(heightBottomSheetOrigin);
                bottomSheetBehavior.setHideable(false);
            }
        });

        cetSearchBox = findViewById(R.id.et_search_shop);
        cetSearchBox.setHint(cetSearchBox.getHint());
        cetSearchBox.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) {
                        bottomSheetBehavior.setPeekHeight(heightBottomSheetOrigin);
                        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    }
                }
            }
        });

        cetSearchBox.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                if (isSelectSearch)
                    return;

                if (editable.length() > 0) {
                    recyclerViewBrand.setVisibility(View.VISIBLE);
                    if (timer != null) {
                        timer.cancel();
                    }
                    timer = new Timer();
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    searchText = cetSearchBox.getText().toString();
                                    filterNameAdress(searchText);
                                }
                            });

                        }
                    }, 600);
                } else {
                    if (timer != null) {
                        timer.cancel();
                    }
                    timer = new Timer();
                    timer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    shopLocationAdapter.removeAll();
                                    searchText = cetSearchBox.getText().toString();
                                    filterNameAdress(searchText);
                                }
                            });

                        }
                    }, 600);
                    errorHandleView.setVisibility(View.GONE);
                }
            }
        });

        findViewById(R.id.icon_search).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clearKeyBoard(true);
            }
        });
        ImageView btnCurrentLocation = findViewById(R.id.btn_current_location);
        btnCurrentLocation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clearKeyBoard(true);
                moveCameraCurrentLocaiton();
            }
        });
    }

    private void clearKeyBoard(boolean isHideKey) {
        if (isHideKey)
            SeatelUtils.Companion.hideKeyboard(LocationShopMapActivity.this);
        cetSearchBox.clearFocus();
        errorHandleView.requestFocus();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        locationRequestController.onPermissionResult(requestCode, permissions, grantResults);
    }


    private void moveToDefaultAfterDeniedPermission() {
        if (mMap != null && currentLocation != null) {
            LatLng gps = new LatLng(11.541889, 104.921333);
            if (shopLocationSearchData != null) {
                if (shopLocationSearchData.size() > 0) {
                    SeatelShopLocationModel data = shopLocationSearchData.get(0);
                    gps = new LatLng(data.getLatitude(), data.getLongitude());
                }
            }
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(gps, mapZoom));
        }
    }

    private void setUpMap() {
        ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMapAsync(this);
    }

    public static void lunch(Context context) {
        Intent intent = new Intent(context, LocationShopMapActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    private void setupToolbar() {

        if (toolbarMap != null) {
            setSupportActionBar(toolbarMap);
        }
        mActionBarMap = getSupportActionBar();
        if (mActionBarMap != null) {
            mActionBarMap.setDisplayHomeAsUpEnabled(true);
            mActionBarMap.setDisplayShowTitleEnabled(false);
            mActionBarMap.setHomeAsUpIndicator(R.drawable.ic_left_back);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        setUpMap();
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        activityExitLeftAnimation();
        clearKeyBoard(true);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        if (mMap != null) {
            return;
        }
        mMap = googleMap;
        startShowMap();
    }

    private void moveCameraCurrentLocaiton() {
        if (mMap != null && currentLocation != null) {
            LatLng gps = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(gps, mapZoom));
        }

    }

    @Override
    protected boolean isDisplayToolbar() {
        return false;
    }

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) {

    }

    private void requestPermissionPhoneCall() {
        mPhoneNumberRequest = PermissionUtil.with(this).request(Manifest.permission.CALL_PHONE).onAllGranted(new PermissionUtil.Func() {
            @Override
            protected void call() {
                showCallDialScreenPhone(phoneForCall);
            }
        }).onAnyDenied(new PermissionUtil.Func() {
            @Override
            protected void call() {

            }
        }).askPermission(Constant.REQUEST_PHONE_PERMISSION_CODE);
    }

    public void showCallDialog(String phoneCall) {
        phoneForCall = phoneCall;
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            showCallDialScreenPhone(phoneCall);
        } else {
            requestPermissionPhoneCall();
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, Constant.REQUEST_PHONE_CALL);
        }
    }

    private void showCallDialScreenPhone(String phoneCall) {
        Intent intent = new Intent(Intent.ACTION_DIAL);
        intent.setData(Uri.parse("tel:" + phoneCall));
        this.startActivity(intent);
    }
}
