package com.example.quiz;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.anggastudio.printama.Printama;
import com.example.quiz.data.adapter.LastBetsAdapter;
import com.example.quiz.data.model.Course;
import com.example.quiz.data.model.Pari;
import com.example.quiz.data.model.ParisResponse;
import com.example.quiz.databinding.FragmentDerniersParisBinding;
import com.example.quiz.utils.BitMapUtils;
import com.example.quiz.utils.BluetoothUtils;
import com.example.quiz.utils.LoaderDialog;
import com.example.quiz.utils.MessageDialog;
import com.example.quiz.utils.MobiIotPrinterManager;
import com.example.quiz.utils.Result;
import com.example.quiz.utils.SharedPrefsHelper;
import com.example.quiz.utils.SunmiPrinterManager;
import com.example.quiz.viewModel.LogsViewModel;
import com.example.quiz.viewModel.PariViewModel;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import dagger.hilt.android.AndroidEntryPoint;

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

@AndroidEntryPoint
public class DerniersParis extends Fragment {

    FragmentDerniersParisBinding binding;

    LogsViewModel logsViewModel;


    LoaderDialog loader;

    SharedPrefsHelper prefsHelper;
    PariViewModel viewModel;

    AlertDialog dialog;

    LastBetsAdapter adapter;
    String mobileName;

    MutableLiveData<Boolean> isPrinterConnected = new MutableLiveData<>(false);

    SunmiPrinterManager sunmiPrinterManager;

    Map<String, Integer> listProduits = Map.of("QUINTE", 5, "QUARTE", 4, "TIERCE", 3, "COUPLE_GAGNANT", 2, "COUPLE_PLACE", 2);

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

    // TODO: Rename and change types and number of parameters
    public static DerniersParis newInstance() {
        DerniersParis fragment = new DerniersParis();
        Bundle args = new Bundle();
          fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        prefsHelper = SharedPrefsHelper.getInstance(getContext());
        mobileName = Build.MANUFACTURER;
        sunmiPrinterManager = SunmiPrinterManager.getInstance(requireContext());
        if(Build.MANUFACTURER.toLowerCase().contains("sunmi")){
            sunmiPrinterManager.connectPrinter(status ->{
                isPrinterConnected.setValue(status);
            });
        }else{
            MobiIotPrinterManager.getInstance().init(getContext());
        }
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding =  FragmentDerniersParisBinding.inflate(inflater, container, false);
        loader = 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);
        binding.lastBetsRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        viewModel = new ViewModelProvider(this).get(PariViewModel.class);
        _getLastBets();
    }

   void _getLastBets(){
       viewModel.getDerniersParis(prefsHelper.get("id")).observe(getViewLifecycleOwner(), new Observer<Result<List<ParisResponse>>>() {
           @Override
           public void onChanged(Result<List<ParisResponse>> listResult) {
               switch (listResult.status){
                   case LOADING:
                       loader.show("Chargement des derniers paris");
                       break;
                   case ERROR:
                       loader.dismiss();
                       MessageDialog.showError(getContext(), listResult.message);
                       break;
                   case SUCCESS:
                       loader.dismiss();
                       if(adapter == null){
                           adapter = new LastBetsAdapter(listResult.data);
                       }else{
                           adapter.setData(listResult.data);
                       }

                       logsViewModel.insertLog(prefsHelper.get("id"), "LAST BETS", "Affichage derniers paris", System.currentTimeMillis());
                       adapter.setPariClickListener(new LastBetsAdapter.onPariClickListener() {
                           @Override
                           public void onItemClick(ParisResponse pari) {
                               if(pari.getStatutPari() != null && pari.getStatutPari() != ParisResponse.StatutPari.ENREGISTRE){
                                   MessageDialog.showError(getContext(), "Ce pari ne peut pas être réimprimé!");
                                   return;
                               }
                               _showPariDialog(pari);
                           }
                           @Override
                           public void onItemCancel(ParisResponse pari) {
                               if(pari.getStatutPari() != null && pari.getStatutPari() != ParisResponse.StatutPari.ENREGISTRE){
                                   MessageDialog.showError(getContext(), "Ce pari ne peut pas être annulé");
                                   return;
                               }
                               _cancelConfirmationDialog(pari);
                           }
                       });
                       binding.lastBetsRecyclerView.setAdapter(adapter);
                       break;
               }
           }
       });
    }

    void _cancelConfirmationDialog(ParisResponse pari){
        new AlertDialog.Builder(getContext())
                .setTitle("Annulation du pari")
                .setMessage("Êtes-vous sûr de vouloir annuler le pari "+pari.getNumeroTicket()+" ?")
                .setPositiveButton("Oui", (cancelDialog, which) -> {
                    _cancelPari(pari);
                    cancelDialog.dismiss();
                })
                .setNegativeButton("Non", (cancelDialog, which) -> {
                    cancelDialog.dismiss();
                }).show();
    }

    void _cancelPari(ParisResponse pari){
        String agentId = prefsHelper.get("id");
        viewModel.annulerPari(pari.getNumeroTicket(), agentId).observe(getViewLifecycleOwner(), new Observer<Result<ParisResponse>>() {
            @Override
            public void onChanged(Result<ParisResponse> result) {
                switch (result.status){
                    case LOADING:
                        loader.show("Annulation du pari");
                        break;
                    case ERROR:
                        loader.dismiss();
                        MessageDialog.showError(getContext(), result.message);
                        break;
                    case SUCCESS:
                        loader.dismiss();
                        MessageDialog.showSuccess(getContext(), "Pari annulé avec succès");
                        _getLastBets();
                        break;
                }
            }
        });
    }


    @SuppressLint({"MissingInflatedId", "SetTextI18n"})
    void _showPariDialog(ParisResponse pari){
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(R.layout.pari_confirmation, null);
        TextView numero_course = (TextView) view.findViewById(R.id.alert_course_numero);
        numero_course.setText("Numero Course: "+String.valueOf(pari.getCourseId()));
        TextView alert_pari_type = (TextView) view.findViewById(R.id.alert_pari_type);
        alert_pari_type.setText(String.valueOf(pari.getTypesParisMises().get(0).getTypePari()));
        TextView is_elargie = (TextView) view.findViewById(R.id.alert_is_elargie);
        List<String> selectedHorses = Arrays.stream(pari.getCombinaison().split(","))
                .map(String::trim)
                .collect(Collectors.toList());
        is_elargie.setText(selectedHorses.size() > listProduits.get(pari.getTypesParisMises().get(0).getTypePari())?"CE":"SI");
        TextView alert_combinaison = (TextView) view.findViewById(R.id.alert_combinaison);
        alert_combinaison.setText(selectedHorses.stream()
                .map(String::valueOf)
                .collect(Collectors.joining("-")));
        TextView aler_coeff = (TextView) view.findViewById(R.id.alert_coeff);
        aler_coeff.setText("Coef:"+String.valueOf(pari.getCoefficient()));
        TextView alert_montant = (TextView) view.findViewById(R.id.alert_montant);
        alert_montant.setText("Montant: "+String.valueOf(pari.getTypesParisMises().get(0).getMiseTotale())+" CFA");
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setView(view);
        builder.setCancelable(false);
        dialog = builder.create();
        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        view.findViewById(R.id.alert_validate).setOnClickListener(v->{
            if(mobileName.toLowerCase().contains("sunmi")){
                if(isPrinterConnected.getValue() != null && !isPrinterConnected.getValue()){
                    sunmiPrinterManager.connectPrinter(status ->{
                        isPrinterConnected.setValue(status);
                    });
                }
                switch (sunmiPrinterManager.printerStatus()){
                    case 2:{
                        MessageDialog.showError(getContext(), "L'imprimante n'est pas connectée!");
                        return;
                    }
                    case 3:{
                        MessageDialog.showError(getContext(), "L'imprimante n'est pas disponible!");
                        return;
                    }
                    case 4:{
                        MessageDialog.showError(getContext(), "Veuillez insérer du papier dans l'imprimante, SVP!");
                        return;
                    }
                    case 5: {
                        MessageDialog.showError(getContext(), "Suchauffe iminante de l'imprimante, Veuillez laisser reposer!");
                        return;
                    }
                    case 6: {
                        MessageDialog.showError(getContext(), "Le capot est ouvert, veuillez fermer SVP!");
                        return;
                    }

                }
            }else{
                try {
                    int printerStatus = MobiIotPrinterManager.getInstance().getPrinterStatus();
                    if(printerStatus != 1){
                        MessageDialog.showError(getContext(), "L'imprimante n'est pas connectée!");
                        return;
                    }
                } catch (RemoteException e) {
                    throw new RuntimeException(e);
                }
            }
            try {
                _printPari(pari);
                dialog.dismiss();
            } catch (WriterException e) {
                throw new RuntimeException(e);
            }
        });
        view.findViewById(R.id.alert_cancel).setOnClickListener(v -> {
            dialog.dismiss();
        });
        dialog.show();
    }



     void _printPari(ParisResponse pari) throws WriterException {
         Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pmu_logo);
         Bitmap barcode = BitMapUtils.generateBarcodeBitmap(pari.getNumeroTicket(), 384, 100);
         StringBuilder tspl = new StringBuilder();
         tspl.append("Bamako").append("\n");
         tspl.append(pari.getCourseNom()).append("\n");
         OffsetDateTime dateTime = OffsetDateTime.parse(pari.getHeureDepartPrevue() != null ? pari.getHeureDepartPrevue() : OffsetDateTime.now().toString());
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
         String formattedDate = dateTime.format(formatter);
         tspl.append(formattedDate).append("\n");
         tspl.append("Course ").append(BitMapUtils.formatMontant(pari.getCourseId())).append("\n");
         tspl.append(sunmiPrinterManager.separationText()+"\n");
         List<String> selectedHorses = Arrays.stream(pari.getCombinaison().split(",")).collect(Collectors.toList());
         boolean isElargie = selectedHorses.size()> listProduits.get(pari.getTypesParisMises().get(0).getTypePari());
         String typePari = pari.getTypesParisMises().get(0).getTypePari();
         tspl.append(isElargie?typePari+"/Elargie":typePari).append("\n");
         tspl.append(pari.getFormules().contains("FORMULE_COMPLETE") ?"COMBINAISON COMPLETE"+"\n":"");
         String combinationText = BitMapUtils.formatLineWithNumbers(selectedHorses.stream().map(String::valueOf).toArray(String[]::new), "-", listProduits.get(pari.getTypesParisMises().get(0).getTypePari()));
         tspl.append(combinationText).append("\n");
         tspl.append("COEF:   ").append(BitMapUtils.formatMontant(pari.getCoefficient()));
         tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n");
         tspl.append("MONTANT: ").append(BitMapUtils.formatMontant(pari.getMiseTotale())).append(" XOF");
         tspl.append("\n").append(sunmiPrinterManager.separationText()).append("\n");
         tspl.append("AGENT: ").append(pari.getAgentCode()).append("\n");
         tspl.append("DATE:  ").append(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss").format(OffsetDateTime.parse(pari.getDateHeurePrise()))).append("\n");
         if(Build.MANUFACTURER.toLowerCase().contains("sunmi")){
             if(Boolean.FALSE.equals(isPrinterConnected.getValue())){
                 MessageDialog.showError(getContext(), "Printer not connected");
                 return;
             }
             sunmiPrinterManager.printPari(BitMapUtils.resizeToPrinterWidth(bitmap, 384), barcode, pari.getNumeroTicket(), tspl.toString(), new SunmiPrinterManager.PrintStatusListener() {
                 @Override
                 public void onStatusChanged(boolean status) {
                    if(!status){
                        new Handler(Looper.getMainLooper()).post(new Runnable() {
                            @Override
                            public void run() {
                                MessageDialog.showError(getContext(), "Erreur lors de l'impression."+"\n"+"Veuillez rééssayer SVP");
                            }
                        });
                    }
                 }
             });
             return;
         }
         MobiIotPrinterManager.getInstance().printPari(BitMapUtils.bitmapToBmp(BitMapUtils.resizeToPrinterWidth(bitmap, 384)), BitMapUtils.bitmapToBmp(barcode), pari.getNumeroTicket(), tspl, new MobiIotPrinterManager.MobiIotPrinterStatus() {
             @Override
             public void printStatusCode(int status) {
                 if(status != 1){
                     new Handler(Looper.getMainLooper()).post(new Runnable() {
                         @Override
                         public void run() {
                             MessageDialog.showError(getContext(), "Erreur lors de l'impression."+"\n"+"Veuillez rééssayer SVP");
                         }
                     });
                 }
             }
         });
//        try {
//            if (BluetoothUtils.needsBluetoothPermissions()) {
//                if (!BluetoothUtils.hasBluetoothPermission(requireContext())) {
//                    // Demande la permission si non accordée
//                    BluetoothUtils.requestBluetoothPermission(requireActivity());
//                    return; // arrête ici, la popup va apparaître
//                }
//            }
//            // 2️⃣ Permission OK, on peut afficher la liste
//
//            Printama.with(getContext()).printTextBuilder(tspl, bitmap, pari.getNumeroTicket(), barcode, new Printama.PrintCallback() {
//                @Override
//                public void onResult(boolean success, String errorMessage) {
//                    if(!success){
//                        MessageDialog.showError(getContext(), errorMessage);
//                    }else{
//                        MessageDialog.showSuccess(getContext(), "Pari imprimé avec succès");
//                    }
//                }
//            });
//        } catch (SecurityException e) {
//            Toast.makeText(requireContext(),
//                    "Permission Bluetooth non accordée", Toast.LENGTH_SHORT).show();
//        }
    }



    @Override
    public void onResume() {
        super.onResume();
        AppCompatActivity activity = (AppCompatActivity) getActivity();
        if(activity!=null){
            MaterialToolbar toolbar = activity.findViewById(R.id.toolbar);
            activity.setSupportActionBar(toolbar);
            toolbar.setTitle("Derniers Paris");
        }
    }
}