package com.example.quiz;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.quiz.data.adapter.MultiTypeOfBetsAdapter;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.Restriction;
import com.example.quiz.data.model.TypeOfBet;
import com.example.quiz.data.model.dtos.auth.User;
import com.example.quiz.databinding.FragmentAgentDetailsBinding;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.viewModel.AgentViewModel;
import com.example.quiz.viewModel.LogsViewModel;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import dagger.hilt.android.AndroidEntryPoint;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link AgentDetails#newInstance} factory method to
 * create an instance of this fragment.
 */
@AndroidEntryPoint
public class AgentDetails extends Fragment {

    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private String agentId;
    private FragmentAgentDetailsBinding binding;
    MultiTypeOfBetsAdapter multiTypeOfBetsAdapter;
    LogsViewModel logsViewModel;
    private AgentViewModel agentViewModel;

    private boolean userInteraction = false;

    private User agent;

    private Restriction allowedBetTypes;

    private SharedPrefsHelper prefsHelper;

    private LoaderDialog loaderDialog;

    public AgentDetails() {
        // Required empty public constructor
    }

    private static final String AGENT_ID = "agentId";

    // TODO: Rename and change types and number of parameters
    public static AgentDetails newInstance(User agent) {
        AgentDetails fragment = new AgentDetails();
        Bundle args = new Bundle();
        args.putString(AGENT_ID, String.valueOf(agent.getId()));
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            agentId = getArguments().getString(AGENT_ID);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        binding = FragmentAgentDetailsBinding.inflate(inflater, container, false);
        agentViewModel = new ViewModelProvider(this).get(AgentViewModel.class);
        allowedBetTypes = new Restriction();
        prefsHelper = SharedPrefsHelper.getInstance(getContext());
        loaderDialog = new LoaderDialog(getContext());
        logsViewModel = new ViewModelProvider(this).get(LogsViewModel.class);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        loadAgentDetails(agentId);
        binding.switchAccess.setOnCheckedChangeListener((compoundButton, b) -> {
                if(!userInteraction){
                    return;
                }
                String message = b ? "Voulez-vous activer l'accès à l'agent ?" : "Voulez-vous désactiver l'accès à l'agent ?";
                new AlertDialog.Builder(getContext())
                        .setTitle("Activation de l'accès")
                        .setMessage(message)
                        .setPositiveButton("Oui", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                if(prefsHelper.get("id")== null){
                                    MessageDialog.showError(getContext(), "Veuillez vous connecter");
                                    return;
                                }
                                String masterId = prefsHelper.get("id");
                                agentViewModel.setAccess(masterId, agentId, !b).observe(getViewLifecycleOwner(), new Observer<Result<Void>>() {
                                    @Override
                                    public void onChanged(Result<Void> voidResult) {
                                        switch (voidResult.status){
                                            case LOADING:{
                                                loaderDialog.show("Chargement des agents");
                                                break;
                                            }
                                            case ERROR:{
                                                loaderDialog.dismiss();
                                                MessageDialog.showError(getContext(), voidResult.message);
                                                break;
                                            }
                                            case SUCCESS:{
                                                loaderDialog.dismiss();
                                                MessageDialog.showSuccess(getContext(), "L'accès a été mis à jour");
                                                String logsMessage = !b? "Activation de l'accès du sous agent":"Désactivation de l'accès du sous agent";
                                                logsViewModel.insertLog(prefsHelper.get("id"), !b?"ACTIVATION":"DESACTIVATION",message+" "+agent.getCode(), System.currentTimeMillis());
                                                loadAgentDetails(agentId);
                                                break;
                                             }
                                            }
                                        }
                                });
                            }
                        }).setNegativeButton("Non", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                dialogInterface.dismiss();
                            }
                        }).show();
        });
        binding.btnValidate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(prefsHelper.get("id")== null){
                    MessageDialog.showError(getContext(), "Veuillez vous connecter");
                    return;
                }
                if(allowedBetTypes.getAllowedBetTypes() == null || allowedBetTypes.getAllowedBetTypes().isEmpty()){
                    MessageDialog.showError(getContext(), "Veuillez sélectionner au moins un type de paris");
                    return;
                }
                if(agent == null){
                    MessageDialog.showError(getContext(), "Veuillez charger les détails de l'agent");
                    return;
                }
                String masterId = prefsHelper.get("id");
                new AlertDialog.Builder(getContext())
                        .setTitle("Valider la sélection")
                        .setMessage("Êtes-vous sûr de vouloir valider la sélection ?")
                        .setPositiveButton("Oui", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                agentViewModel.setRestrictions(masterId, agentId, allowedBetTypes).observe(getViewLifecycleOwner(), new Observer<Result<Void>>() {
                                    @Override
                                    public void onChanged(Result<Void> voidResult) {
                                        switch (voidResult.status){
                                            case LOADING:{
                                                loaderDialog.show("Chargement des agents");
                                                break;
                                            }
                                            case ERROR:{
                                                loaderDialog.dismiss();
                                                MessageDialog.showError(getContext(), voidResult.message);
                                                break;
                                            }
                                            case SUCCESS:{
                                                loaderDialog.dismiss();
                                                logsViewModel.insertLog(prefsHelper.get("id"), "MIS A JOUR PRODUIT", "Mise à jour des types de paris"+" "+agent.getCode()+": "+allowedBetTypes.getAllowedBetTypes().stream().map(Enum::toString).collect(Collectors.joining(",")), System.currentTimeMillis());
                                                MessageDialog.showSuccess(getContext(), "Les types de paris ont été mises à jour");
                                                loadAgentDetails(agentId);
                                                break;
                                            }
                                            default:{
                                            }
                                        }
                                    }
                                });
                            }
                        })
                        .setNegativeButton("Non", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                dialogInterface.dismiss();
                            }
                        })
                        .show();
             }
        });
    }

    private void loadAgentDetails(String slaveId){
        agentViewModel.getAgentById(slaveId).observe(getViewLifecycleOwner(), new Observer<Result<User>>() {
            @Override
            public void onChanged(Result<User> userResult) {
                switch (userResult.status){
                    case LOADING:{
                        loaderDialog.show("Chargement des agents");
                        break;
                    }
                    case ERROR:{
                        loaderDialog.dismiss();
                        MessageDialog.showError(getContext(), userResult.message);
                        break;
                    }
                    case SUCCESS:{
                        loaderDialog.dismiss();
                        agent = userResult.data;
                        binding.txtCode.setText(agent.getCode());
                        String adresse;
                        if(agent.getVille() != null && agent.getAdresse() != null){
                            adresse = agent.getVille()+"; "+agent.getAdresse();
                        }else{
                            adresse = "Pas d'adresse";
                        }
                        binding.txtAdresse.setText(adresse);
                        userInteraction = false;
                        binding.switchAccess.setChecked(agent.getStatut().equals("ACTIF"));
                        userInteraction = true;
                        loadAvailableBets(String.valueOf(agent.getId()));
                        break;
                    }
                    default:{
                        break;
                    }
                }
            }
        });
    }

    private void loadAvailableBets(String id){
        agentViewModel.getAvailableBets(id).observe(getViewLifecycleOwner(), new Observer<Result<List<Course.TypeParis>>>() {
            @Override
            public void onChanged(Result<List<Course.TypeParis>> listResult) {
                switch (listResult.status){
                    case LOADING:{
                        loaderDialog.show("Chargement des paris disponibles");
                        break;
                    }
                    case ERROR:{
                        loaderDialog.dismiss();
                        MessageDialog.showError(getContext(), listResult.message);
                    }
                    case SUCCESS:{
                        loaderDialog.dismiss();
                        List<TypeOfBet> types = createTypeOfBetList();
                        multiTypeOfBetsAdapter = new MultiTypeOfBetsAdapter(types);
                        multiTypeOfBetsAdapter.preSelectAvailableBets(listResult.data);
                        binding.betsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
                        binding.betsRecyclerView.setAdapter(multiTypeOfBetsAdapter);
                        List<Course.TypeParis> selectedTypes = multiTypeOfBetsAdapter.getSelectedItems().stream().map(TypeOfBet::getName).collect(Collectors.toList());
                        allowedBetTypes.setAllowedBetTypes(selectedTypes);
                        multiTypeOfBetsAdapter.setOnItemClickListener(new MultiTypeOfBetsAdapter.onItemClickListener() {
                            @Override
                            public void onItemClick(TypeOfBet type, boolean isChecked) {
                                List<Course.TypeParis> selectedTypes = multiTypeOfBetsAdapter.getSelectedItems().stream().map(TypeOfBet::getName).collect(Collectors.toList());
                                allowedBetTypes.setAllowedBetTypes(selectedTypes);
                            }
                            @Override
                            public void onItemsSelected(List<TypeOfBet> selectedItems) {
                            }
                        });
                    }
                    default:{
                        break;
                    }
                }
            }
        });
    }

    private List<TypeOfBet> createTypeOfBetList() {
        List<TypeOfBet> types = new ArrayList<>();

        // 1. COUPLE GAGNANT
        TypeOfBet coupleGagnant = new TypeOfBet(
                "Couple Gagnant",           // label
                Course.TypeParis.COUPLE_GAGNANT,  // name
                2                           // numberOfHorse (2 chevaux)
        );
        types.add(coupleGagnant);

        // 2. COUPLE PLACE
        TypeOfBet couplePlace = new TypeOfBet(
                "Couple Place",             // label
                Course.TypeParis.COUPLE_PLACE,    // name
                2                           // numberOfHorse (2 chevaux)
        );
        types.add(couplePlace);

        // 3. TIERCE
        TypeOfBet tierce = new TypeOfBet(
                "Tiercé",                   // label
                Course.TypeParis.TIERCE,          // name
                3                           // numberOfHorse (3 chevaux)
        );
        types.add(tierce);

        // 4. QUARTE
        TypeOfBet quarte = new TypeOfBet(
                "Quarté",                   // label
                Course.TypeParis.QUARTE,          // name
                4                           // numberOfHorse (4 chevaux)
        );
        types.add(quarte);

        // 5. QUINTE (optionnel)
        TypeOfBet quinte = new TypeOfBet(
                "Quinté",                   // label
                Course.TypeParis.QUINTE,          // name
                5                           // numberOfHorse (5 chevaux)
        );
        types.add(quinte);

        return types;
    }
}