package com.example.pap_teste;

import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AlertDialog;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;

import com.google.firebase.FirebaseApp;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

    public static final String EXTRA_ACTION_MODE = "extra_action_mode";
    public static final String EXTRA_DISPLAY_NAME = "extra_display_name";
    public static final String EXTRA_EMAIL = "extra_email";
    public static final String EXTRA_ACCOUNT_TYPE = "extra_account_type";
    public static final String EXTRA_ROLE = "extra_role";
    private static final String PREFS_NAME = "pap_prefs";
    private static final String KEY_HAS_CREATED_ACCOUNT = "has_created_account";

    public enum AccountType {
        CLIENTE, ESTABELECIMENTO
    }

    public enum AccountAction {
        ENTRAR, CRIAR
    }

    private AccountType selectedAccountType = AccountType.CLIENTE;
    private AccountAction selectedAccountAction = AccountAction.ENTRAR;

    private Button btnCliente;
    private Button btnEstabelecimento;
    private Button btnEntrar;
    private Button btnCriarConta;
    private Button btnPrimaryAction;
    private EditText inputName;
    private EditText inputEmail;
    private EditText inputPassword;
    private EditText inputOwnerPhone;
    private EditText inputEstablishmentName;
    private EditText inputEstablishmentEmail;
    private EditText inputEstablishmentPhone;
    private android.widget.TextView txtForgotPassword;
    private android.widget.ImageView iconPasswordVisibility;
    private boolean isPasswordVisible = false;
    private boolean hasCreatedAccount;
    private FirebaseAuth firebaseAuth;
    private DatabaseReference databaseReference;

    private final ActivityResultLauncher<String[]> permissionRequest = registerForActivityResult(
            new ActivityResultContracts.RequestMultiplePermissions(), result -> {
                Boolean fineLocationGranted = result.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false);
                Boolean bluetoothScanGranted = true;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    bluetoothScanGranted = result.getOrDefault(Manifest.permission.BLUETOOTH_SCAN, false);
                }

                if (fineLocationGranted != null && fineLocationGranted) {
                    // Precise location access granted.
                } else {
                    Toast.makeText(this, "A permissão de localização é necessária para o check-in.", Toast.LENGTH_LONG)
                            .show();
                }
            });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        FirebaseApp.initializeApp(this);
        firebaseAuth = FirebaseAuth.getInstance();
        databaseReference = FirebaseDatabase.getInstance().getReference();

        bindViews();
        setupTypeToggle();
        setupActionToggle();
        setupPrimaryAction();
        checkPermissions();
    }

    private void checkPermissions() {
        List<String> permissionsNeeded = new ArrayList<>();
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
                permissionsNeeded.add(Manifest.permission.BLUETOOTH_SCAN);
            }
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                permissionsNeeded.add(Manifest.permission.BLUETOOTH_CONNECT);
            }
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
                permissionsNeeded.add(Manifest.permission.READ_MEDIA_IMAGES);
            }
        } else {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                permissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
            }
        }

        if (!permissionsNeeded.isEmpty()) {
            new AlertDialog.Builder(this)
                    .setTitle("Permissões Necessárias")
                    .setMessage("Para o correto funcionamento do check-in, serviços de proximidade e fotos da galeria, precisamos de algumas permissões.")
                    .setPositiveButton("Configurar", (dialog, which) -> {
                        permissionRequest.launch(permissionsNeeded.toArray(new String[0]));
                    })
                    .setNegativeButton("Agora Não", null)
                    .show();
        }
    }

    private void bindViews() {
        btnCliente = findViewById(R.id.btnCliente);
        btnEstabelecimento = findViewById(R.id.btnEstabelecimento);
        btnEntrar = findViewById(R.id.btnEntrar);
        btnCriarConta = findViewById(R.id.btnCriarConta);
        btnPrimaryAction = findViewById(R.id.btnFinalCriarConta);
        inputName = findViewById(R.id.inputName);
        inputEmail = findViewById(R.id.inputEmail);
        inputPassword = findViewById(R.id.inputPassword);
        inputOwnerPhone = findViewById(R.id.inputOwnerPhone);
        inputEstablishmentName = findViewById(R.id.inputEstablishmentName);
        inputEstablishmentEmail = findViewById(R.id.inputEstablishmentEmail);
        inputEstablishmentPhone = findViewById(R.id.inputEstablishmentPhone);
        txtForgotPassword = findViewById(R.id.txtForgotPassword);
        iconPasswordVisibility = findViewById(R.id.iconPasswordVisibility);
        
        setupPasswordFeatures();
    }
    
    private void setupPasswordFeatures() {
        iconPasswordVisibility.setOnClickListener(v -> {
            isPasswordVisible = !isPasswordVisible;
            if (isPasswordVisible) {
                inputPassword.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
                iconPasswordVisibility.setImageResource(R.drawable.ic_visibility);
            } else {
                inputPassword.setInputType(android.text.InputType.TYPE_CLASS_TEXT | android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD);
                iconPasswordVisibility.setImageResource(R.drawable.ic_visibility_off);
            }
            inputPassword.setSelection(inputPassword.getText().length());
        });
        
        txtForgotPassword.setOnClickListener(v -> {
            String email = inputEmail.getText().toString().trim();
            if (TextUtils.isEmpty(email)) {
                Toast.makeText(this, "Por favor, introduza o seu email primeiro.", Toast.LENGTH_SHORT).show();
                return;
            }
            
            new AlertDialog.Builder(this)
                .setTitle("Recuperar palavra-passe")
                .setMessage("Deseja enviar um email de recuperação para " + email + "?")
                .setPositiveButton("Sim", (dialog, which) -> {
                    if (firebaseAuth != null) {
                        firebaseAuth.sendPasswordResetEmail(email)
                            .addOnCompleteListener(task -> {
                                if (task.isSuccessful()) {
                                    Toast.makeText(MainActivity.this, "Email de recuperação enviado!", Toast.LENGTH_LONG).show();
                                } else {
                                    Toast.makeText(MainActivity.this, "Falha ao enviar email. Verifique se o endereço está correto.", Toast.LENGTH_LONG).show();
                                }
                            });
                    }
                })
                .setNegativeButton("Não", null)
                .show();
        });
    }

    private void setupTypeToggle() {
        btnCliente.setOnClickListener(v -> {
            selectedAccountType = AccountType.CLIENTE;
            updateTypeButtons();
        });
        btnEstabelecimento.setOnClickListener(v -> {
            selectedAccountType = AccountType.ESTABELECIMENTO;
            updateTypeButtons();
        });
        updateTypeButtons();
    }

    private void setupActionToggle() {
        btnEntrar.setOnClickListener(v -> {
            selectedAccountAction = AccountAction.ENTRAR;
            updateActionButtons();
        });
        btnCriarConta.setOnClickListener(v -> {
            selectedAccountAction = AccountAction.CRIAR;
            updateActionButtons();
        });
        updateActionButtons();
    }

    private void setupPrimaryAction() {
        btnPrimaryAction.setOnClickListener(v -> handlePrimaryAction());
        updatePrimaryActionState();
    }

    private void updateTypeButtons() {
        setSelectedState(btnCliente, selectedAccountType == AccountType.CLIENTE);
        setSelectedState(btnEstabelecimento, selectedAccountType == AccountType.ESTABELECIMENTO);
        updateInputVisibility();
    }

    private void updateActionButtons() {
        setSelectedState(btnEntrar, selectedAccountAction == AccountAction.ENTRAR);
        setSelectedState(btnCriarConta, selectedAccountAction == AccountAction.CRIAR);
        updatePrimaryActionState();
    }

    private void setSelectedState(Button button, boolean isSelected) {
        int selectedTextColor = Color.WHITE;
        int defaultTextColor = Color.parseColor("#231F1F");
        button.setBackgroundResource(isSelected ? R.drawable.tab_selected : R.drawable.tab_unselected);
        button.setTextColor(isSelected ? selectedTextColor : defaultTextColor);
    }

    private void updatePrimaryActionState() {
        boolean creatingAccount = selectedAccountAction == AccountAction.CRIAR;
        btnPrimaryAction.setText(creatingAccount ? "Criar Conta" : "Entrar");
        updateInputVisibility();
    }

    private void updateInputVisibility() {
        boolean creatingAccount = selectedAccountAction == AccountAction.CRIAR;
        boolean isEstablishment = selectedAccountType == AccountType.ESTABELECIMENTO;

        inputName.setHint(isEstablishment ? "Nome do proprietário" : "O seu nome");
        inputEmail.setHint(isEstablishment ? "Email do proprietário" : "Email");

        inputName.setVisibility(creatingAccount ? View.VISIBLE : View.GONE);
        inputOwnerPhone.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
        inputEstablishmentName.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
        inputEstablishmentEmail.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
        inputEstablishmentPhone.setVisibility(creatingAccount && isEstablishment ? View.VISIBLE : View.GONE);
        
        if (txtForgotPassword != null) {
            txtForgotPassword.setVisibility(creatingAccount ? View.GONE : View.VISIBLE);
        }
    }

    private void handlePrimaryAction() {
        String email = inputEmail.getText().toString().trim();
        String password = inputPassword.getText().toString().trim();
        String providedName = inputName.getText().toString().trim();
        String ownerPhone = inputOwnerPhone.getText().toString().trim();
        String establishmentName = inputEstablishmentName.getText().toString().trim();
        String establishmentEmail = inputEstablishmentEmail.getText().toString().trim();
        String establishmentPhone = inputEstablishmentPhone.getText().toString().trim();

        if (TextUtils.isEmpty(email) || TextUtils.isEmpty(password)) {
            Toast.makeText(this, "Preencha email e palavra-passe.", Toast.LENGTH_SHORT).show();
            return;
        }

        boolean creatingAccount = selectedAccountAction == AccountAction.CRIAR;

        if (creatingAccount && !isValidPassword(password)) {
            return;
        }

        if (creatingAccount) {
            if (selectedAccountType == AccountType.CLIENTE && TextUtils.isEmpty(providedName)) {
                Toast.makeText(this, "Indique o seu nome para criar conta.", Toast.LENGTH_SHORT).show();
                return;
            }

            if (selectedAccountType == AccountType.ESTABELECIMENTO) {
                boolean missingOwner = TextUtils.isEmpty(providedName) || TextUtils.isEmpty(ownerPhone);
                boolean missingEstablishment = TextUtils.isEmpty(establishmentName)
                        || TextUtils.isEmpty(establishmentEmail)
                        || TextUtils.isEmpty(establishmentPhone);

                if (missingOwner || missingEstablishment) {
                    Toast.makeText(this, "Preencha os dados do proprietário e do estabelecimento.", Toast.LENGTH_SHORT)
                            .show();
                    return;
                }
            }
        }

        String fallbackName = !TextUtils.isEmpty(providedName) ? providedName : deriveNameFromEmail(email);
        String resolvedRole = getRoleForSelectedType();

        if (creatingAccount) {
            createAccountInFirebase(
                    email,
                    password,
                    providedName,
                    ownerPhone,
                    establishmentName,
                    establishmentEmail,
                    establishmentPhone,
                    fallbackName,
                    resolvedRole);
            return;
        }

        signInExistingAccount(email, password, fallbackName, resolvedRole);
    }

    private String deriveNameFromEmail(String email) {
        if (!email.contains("@")) {
            return "Utilizador";
        }
        String candidate = email.substring(0, email.indexOf("@"));
        if (candidate.isEmpty()) {
            return "Utilizador";
        }
        String firstLetter = candidate.substring(0, 1).toUpperCase();
        String rest = candidate.length() > 1 ? candidate.substring(1) : "";
        return firstLetter + rest;
    }

    private void markAccountCreated() {
        hasCreatedAccount = true;
        SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
        prefs.edit().putBoolean(KEY_HAS_CREATED_ACCOUNT, true).apply();
    }

    private String getRoleForSelectedType() {
        return selectedAccountType == AccountType.ESTABELECIMENTO ? "ADMIN" : "CLIENTE";
    }

    private String buildDocumentId(String email) {
        return email.replace(".", "_").replace("@", "_at_");
    }

    private boolean ensureFirebaseReady() {
        boolean ready = firebaseAuth != null && databaseReference != null;
        if (!ready) {
            Toast.makeText(this, "Ligue-se ao Firebase para continuar.", Toast.LENGTH_SHORT).show();
        }
        return ready;
    }

    private void signInExistingAccount(String email, String password, String fallbackName, String resolvedRole) {
        if (!ensureFirebaseReady()) {
            return;
        }

        firebaseAuth.signInWithEmailAndPassword(email, password)
                .addOnSuccessListener(authResult -> fetchAccountAndNavigate(email, fallbackName, resolvedRole))
                .addOnFailureListener(e -> {
                    android.util.Log.e("LoginError", "SignIn failed", e);
                    Toast.makeText(this, "Não foi possível iniciar sessão: " + e.getMessage(), Toast.LENGTH_SHORT)
                            .show();
                });
    }

    private void createAccountInFirebase(
            String email,
            String password,
            String providedName,
            String ownerPhone,
            String establishmentName,
            String establishmentEmail,
            String establishmentPhone,
            String fallbackName,
            String resolvedRole) {
        if (!ensureFirebaseReady()) {
            return;
        }

        firebaseAuth.createUserWithEmailAndPassword(email, password)
                .addOnSuccessListener(result -> {
                    if (!hasCreatedAccount) {
                        markAccountCreated();
                    }
                    String finalDisplayName = selectedAccountType == AccountType.ESTABELECIMENTO
                            && !TextUtils.isEmpty(establishmentName)
                                    ? establishmentName
                                    : fallbackName;
                    String uid = result.getUser() != null ? result.getUser().getUid() : null;

                    persistAccountInFirebase(
                            email,
                            providedName,
                            resolvedRole,
                            ownerPhone,
                            establishmentName,
                            establishmentEmail,
                            establishmentPhone,
                            uid,
                            () -> {
                                Toast.makeText(this, "Conta criada com sucesso! Carregue em Entrar.", Toast.LENGTH_LONG)
                                        .show();
                                selectedAccountAction = AccountAction.ENTRAR;
                                updateActionButtons();
                            });
                })
                .addOnFailureListener(e -> {
                    android.util.Log.e("LoginError", "CreateUser failed", e);
                    Toast.makeText(this, "Falha ao criar conta: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                });
    }

    private void fetchAccountAndNavigate(String email, String fallbackName, String resolvedRole) {
        if (databaseReference == null) {
            Toast.makeText(this, "Firebase indisponível.", Toast.LENGTH_SHORT).show();
            navigateToDashboard(email, fallbackName, resolvedRole);
            return;
        }

        String documentId = buildDocumentId(email);
        databaseReference.child("users").child(documentId).get().addOnCompleteListener(task -> {
            if (!task.isSuccessful()) {
                android.util.Log.e("LoginError", "Database check failed", task.getException());
                Toast.makeText(this, "Falha ao validar perfil na cloud. A entrar em modo básico.", Toast.LENGTH_SHORT)
                        .show();
                navigateToDashboard(email, fallbackName, resolvedRole);
                return;
            }

            DataSnapshot snapshot = task.getResult();
            if (snapshot == null || !snapshot.exists()) {
                // Toast.makeText(this, "Conta sem perfil na cloud. A entrar em modo básico.",
                // Toast.LENGTH_SHORT).show();
                navigateToDashboard(email, fallbackName, resolvedRole);
                return;
            }

            String accountTypeInFirebase = snapshot.child("accountType").getValue(String.class);
            if (accountTypeInFirebase != null
                    && !accountTypeInFirebase.equalsIgnoreCase(selectedAccountType.name())) {
                Toast.makeText(this, "Tipo de conta não corresponde ao registo no Firebase.", Toast.LENGTH_SHORT)
                        .show();
                return;
            }

            String displayNameFromDb = snapshot.child("displayName").getValue(String.class);
            String establishmentName = snapshot.child("establishmentName").getValue(String.class);
            String ownerName = snapshot.child("ownerName").getValue(String.class);
            String roleFromDb = snapshot.child("role").getValue(String.class);

            String finalDisplayName = !TextUtils.isEmpty(establishmentName)
                    ? establishmentName
                    : !TextUtils.isEmpty(displayNameFromDb) ? displayNameFromDb
                            : !TextUtils.isEmpty(ownerName) ? ownerName
                                    : fallbackName;

            String finalRole = !TextUtils.isEmpty(roleFromDb) ? roleFromDb : resolvedRole;
            navigateToDashboard(email, finalDisplayName, finalRole);
        });
    }

    private void navigateToDashboard(String email, String displayName, String role) {
        Intent nextScreen = selectedAccountType == AccountType.CLIENTE
                ? new Intent(this, ClientDashboardActivity.class)
                : new Intent(this, EstablishmentDashboardActivity.class);

        nextScreen.putExtra(EXTRA_ACTION_MODE, selectedAccountAction.name());
        nextScreen.putExtra(EXTRA_DISPLAY_NAME, displayName);
        nextScreen.putExtra(EXTRA_EMAIL, email);
        nextScreen.putExtra(EXTRA_ACCOUNT_TYPE, selectedAccountType.name());
        nextScreen.putExtra(EXTRA_ROLE, role);
        startActivity(nextScreen);
    }

    private void persistAccountInFirebase(
            String ownerEmail,
            String ownerName,
            String role,
            String ownerPhone,
            String establishmentName,
            String establishmentEmail,
            String establishmentPhone,
            String uid,
            Runnable onSuccess) {
        if (databaseReference == null) {
            Toast.makeText(this, "Firebase indisponível.", Toast.LENGTH_SHORT).show();
            return;
        }

        String documentId = buildDocumentId(ownerEmail);
        Map<String, Object> payload = new HashMap<>();
        if (!TextUtils.isEmpty(uid)) {
            payload.put("uid", uid);
        }
        payload.put("email", ownerEmail);
        payload.put("displayName", ownerName);
        payload.put("role", role);
        payload.put("accountType", selectedAccountType.name());
        payload.put("createdAt", System.currentTimeMillis());

        if (selectedAccountType == AccountType.ESTABELECIMENTO) {
            payload.put("ownerName", ownerName);
            payload.put("ownerEmail", ownerEmail);
            payload.put("ownerPhone", ownerPhone);
            payload.put("establishmentName", establishmentName);
            payload.put("establishmentEmail", establishmentEmail);
            payload.put("establishmentPhone", establishmentPhone);
        }

        databaseReference.child("users").child(documentId).updateChildren(payload)
                .addOnSuccessListener(unused -> {
                    Toast.makeText(this, "Conta guardada na cloud.", Toast.LENGTH_SHORT).show();
                    if (onSuccess != null) {
                        onSuccess.run();
                    }
                })
                .addOnFailureListener(
                        e -> Toast.makeText(this, "Não foi possível guardar na cloud.", Toast.LENGTH_SHORT).show());
    }

    private boolean isValidPassword(String password) {
        if (password.length() < 6) {
            Toast.makeText(this, "A palavra-passe deve ter pelo menos 6 caracteres.", Toast.LENGTH_SHORT).show();
            return false;
        }
        boolean hasLower = false;
        boolean hasDigit = false;
        boolean hasSpecial = false;

        for (char c : password.toCharArray()) {
            if (Character.isLowerCase(c))
                hasLower = true;
            else if (Character.isDigit(c))
                hasDigit = true;
            else if (!Character.isLetterOrDigit(c))
                hasSpecial = true;
        }

        if (!hasLower || !hasDigit || !hasSpecial) {
            Toast.makeText(this, "A palavra-passe deve conter minúsculas, números e símbolos.", Toast.LENGTH_LONG)
                    .show();
            return false;
        }
        return true;
    }
}