package com.example.petstoremobile.fragments.listfragments;

import android.graphics.Color;
import android.os.Bundle;
import android.view.*;
import android.widget.*;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.petstoremobile.api.auth.TokenManager;
import com.example.petstoremobile.databinding.FragmentAnalyticsBinding;
import com.example.petstoremobile.utils.SpinnerUtils;
import com.example.petstoremobile.utils.UIUtils;
import com.example.petstoremobile.viewmodels.AnalyticsViewModel;
import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@AndroidEntryPoint
public class AnalyticsFragment extends Fragment {

    @Inject
    TokenManager tokenManager;

    private FragmentAnalyticsBinding binding;
    private AnalyticsViewModel viewModel;
    private boolean filtersExpanded = false;

    private static final String[] TOP_N_OPTIONS = {"5", "10", "15", "20"};
    private static final int[] TOP_N_VALUES    = { 5,   10,   15,   20 };

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        binding = FragmentAnalyticsBinding.inflate(inflater, container, false);
        viewModel = new ViewModelProvider(this).get(AnalyticsViewModel.class);

        setupFilterPanel();
        setupViewModeToggle();
        observeViewModel();
        viewModel.loadAnalytics();

        binding.btnRefreshAnalytics.setOnClickListener(v -> viewModel.loadAnalytics());
        UIUtils.setupHamburgerMenu(binding.btnHamburgerAnalytics, this);

        return binding.getRoot();
    }

    private static final int COLOR_SELECTED = 0xFF4ECDC4;
    private static final int COLOR_UNSELECTED = 0xFFCBD5E1;

    private void setupViewModeToggle() {
        updateViewModeButtonStyles(viewModel.getViewMode());

        binding.btnMyAnalytics.setOnClickListener(v -> {
            viewModel.setViewMode("mine");
            updateViewModeButtonStyles("mine");
            updateStoreFilterVisibility("mine");
        });

        binding.btnStoreAnalytics.setOnClickListener(v -> {
            viewModel.setViewMode("store");
            updateViewModeButtonStyles("store");
            updateStoreFilterVisibility("store");
        });
    }

    private void updateViewModeButtonStyles(String mode) {
        binding.btnMyAnalytics.setBackgroundTintList(
            android.content.res.ColorStateList.valueOf(mode.equals("mine") ? COLOR_SELECTED : COLOR_UNSELECTED));
        binding.btnStoreAnalytics.setBackgroundTintList(
            android.content.res.ColorStateList.valueOf(mode.equals("store") ? COLOR_SELECTED : COLOR_UNSELECTED));
    }

    private void updateStoreFilterVisibility(String mode) {
        boolean isAdmin = "ADMIN".equalsIgnoreCase(tokenManager.getRole());
        int vis = (isAdmin && mode.equals("store")) ? View.VISIBLE : View.GONE;
        binding.tvStoreFilterLabel.setVisibility(vis);
        binding.spinnerFilterStore.setVisibility(vis);
    }

    // Filter Panel

    private void setupFilterPanel() {
        SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerTopN, TOP_N_OPTIONS);

        // Toggle expand/collapse
        binding.rowFilterHeader.setOnClickListener(v -> toggleFilters());

        // Date pickers
        binding.etFilterStartDate.setOnClickListener(v ->
                UIUtils.showDatePicker(requireContext(), binding.etFilterStartDate, this::updateFilterSummary));
        binding.etFilterEndDate.setOnClickListener(v ->
                UIUtils.showDatePicker(requireContext(), binding.etFilterEndDate, this::updateFilterSummary));

        // Quick presets
        binding.btnPresetToday.setOnClickListener(v -> applyPreset(0, 0));
        binding.btnPreset7D.setOnClickListener(v -> applyPreset(-6, 0));
        binding.btnPreset30D.setOnClickListener(v -> applyPreset(-29, 0));
        binding.btnPreset3M.setOnClickListener(v -> applyPreset(-89, 0));
        binding.btnPreset1Y.setOnClickListener(v -> applyPreset(-364, 0));
        binding.btnPresetAll.setOnClickListener(v -> {
            binding.etFilterStartDate.setText("");
            binding.etFilterEndDate.setText("");
            updateFilterSummary();
        });

        binding.btnFilterApply.setOnClickListener(v -> applyFiltersFromUI());
        binding.btnFilterReset.setOnClickListener(v -> resetFilters());
    }

    private void toggleFilters() {
        filtersExpanded = !filtersExpanded;
        binding.llFilterContent.setVisibility(filtersExpanded ? View.VISIBLE : View.GONE);
        binding.tvFilterToggleIcon.setText(filtersExpanded ? "▲" : "▼");
    }

    private void applyPreset(int startOffset, int endOffset) {
        binding.etFilterStartDate.setText(getDateString(startOffset));
        binding.etFilterEndDate.setText(getDateString(endOffset));
        updateFilterSummary();
        applyFiltersFromUI();
    }

    private void applyFiltersFromUI() {
        AnalyticsViewModel.FilterState filter = new AnalyticsViewModel.FilterState();
        filter.startDate = binding.etFilterStartDate.getText().toString().trim();
        filter.endDate   = binding.etFilterEndDate.getText().toString().trim();

        Object pm = binding.spinnerFilterPayment.getSelectedItem();
        filter.paymentMethod = pm != null ? pm.toString() : "All";

        int topNPos = binding.spinnerTopN.getSelectedItemPosition();
        filter.topN = (topNPos >= 0 && topNPos < TOP_N_VALUES.length) ? TOP_N_VALUES[topNPos] : 5;

        Object store = binding.spinnerFilterStore.getSelectedItem();
        viewModel.setStoreFilter(store != null ? store.toString() : "All Stores");

        updateFilterSummary();
        viewModel.applyFilter(filter);
    }

    private void resetFilters() {
        binding.etFilterStartDate.setText("");
        binding.etFilterEndDate.setText("");
        binding.spinnerTopN.setSelection(0);
        SpinnerUtils.setSelectionByValue(binding.spinnerFilterPayment, "All");
        SpinnerUtils.setSelectionByValue(binding.spinnerFilterStore, "All Stores");
        updateFilterSummary();
        viewModel.resetFilter();
    }

    private void updateFilterSummary() {
        String start = binding.etFilterStartDate.getText().toString().trim();
        String end   = binding.etFilterEndDate.getText().toString().trim();
        if (start.isEmpty() && end.isEmpty()) {
            binding.tvFilterSummary.setText("All time");
        } else if (start.isEmpty()) {
            binding.tvFilterSummary.setText("Up to " + shortDate(end));
        } else if (end.isEmpty()) {
            binding.tvFilterSummary.setText("From " + shortDate(start));
        } else {
            binding.tvFilterSummary.setText(shortDate(start) + " – " + shortDate(end));
        }
    }

    private String shortDate(String date) {
        return (date != null && date.length() >= 10) ? date.substring(5) : date;
    }

    private String getDateString(int offsetDays) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_YEAR, offsetDays);
        return String.format(Locale.US, "%04d-%02d-%02d",
                c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH));
    }

    // ViewModel Observation

    private void observeViewModel() {
        viewModel.getAnalyticsData().observe(getViewLifecycleOwner(), this::computeAndDisplay);

        viewModel.getIsLoading().observe(getViewLifecycleOwner(), loading -> {
            binding.progressBar.setVisibility(loading ? View.VISIBLE : View.GONE);
            if (loading) {
                binding.tvTotalRevenue.setText("Loading...");
                binding.tvTotalTransactions.setText("...");
                binding.tvAvgTransaction.setText("...");
                binding.tvTotalItems.setText("...");
            }
        });

        viewModel.getErrorMessage().observe(getViewLifecycleOwner(), error -> {
            if (error != null) showError(error);
        });

        viewModel.getAvailablePaymentMethods().observe(getViewLifecycleOwner(), methods -> {
            if (methods == null || methods.isEmpty()) return;
            String currentSelection = binding.spinnerFilterPayment.getSelectedItem() != null
                    ? binding.spinnerFilterPayment.getSelectedItem().toString() : "All";
            SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerFilterPayment,
                    methods.toArray(new String[0]));
            SpinnerUtils.setSelectionByValue(binding.spinnerFilterPayment, currentSelection);
        });

        viewModel.getAvailableStores().observe(getViewLifecycleOwner(), stores -> {
            if (stores == null || stores.isEmpty()) return;
            String currentSelection = binding.spinnerFilterStore.getSelectedItem() != null
                    ? binding.spinnerFilterStore.getSelectedItem().toString() : "All Stores";
            SpinnerUtils.setupStringSpinner(requireContext(), binding.spinnerFilterStore,
                    stores.toArray(new String[0]));
            SpinnerUtils.setSelectionByValue(binding.spinnerFilterStore, currentSelection);
            updateStoreFilterVisibility(viewModel.getViewMode());
        });
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

    // Display

    private void computeAndDisplay(AnalyticsViewModel.AnalyticsData data) {
        if (data == null) return;

        // Summary cards
        binding.tvTotalRevenue.setText("$" + data.totalRevenue.setScale(2, RoundingMode.HALF_UP));
        binding.tvTotalTransactions.setText(String.valueOf(data.totalTransactions));
        binding.tvAvgTransaction.setText("$" + data.avgTransaction);
        binding.tvTotalItems.setText(String.valueOf(data.totalItems));

        // Top Revenue Products
        binding.llTopRevenue.removeAllViews();
        if (data.topRevenueProducts != null && !data.topRevenueProducts.isEmpty()) {
            BigDecimal maxRev = data.topRevenueProducts.get(0).getValue();
            if (maxRev.compareTo(BigDecimal.ZERO) == 0) maxRev = BigDecimal.ONE;
            for (Map.Entry<String, BigDecimal> e : data.topRevenueProducts) {
                addBarRow(binding.llTopRevenue, e.getKey(),
                        "$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
                        e.getValue().floatValue() / maxRev.floatValue(), "#ff6b35");
            }
        } else {
            addEmptyRow(binding.llTopRevenue, "No data");
        }

        // Top Quantity Products
        binding.llTopQuantity.removeAllViews();
        if (data.topQuantityProducts != null && !data.topQuantityProducts.isEmpty()) {
            int maxQty = data.topQuantityProducts.get(0).getValue();
            if (maxQty == 0) maxQty = 1;
            for (Map.Entry<String, Integer> e : data.topQuantityProducts) {
                addBarRow(binding.llTopQuantity, e.getKey(), e.getValue() + " units",
                        (float) e.getValue() / maxQty, "#4ecdc4");
            }
        } else {
            addEmptyRow(binding.llTopQuantity, "No data");
        }

        // Payment Methods
        binding.llPaymentMethods.removeAllViews();
        if (data.paymentMethodStats != null && !data.paymentMethodStats.isEmpty()) {
            int maxPay = data.paymentMethodStats.stream().mapToInt(Map.Entry::getValue).max().orElse(1);
            String[] payColors = { "#1a759f", "#ff9f1c", "#577590", "#90be6d" };
            int ci = 0;
            for (Map.Entry<String, Integer> e : data.paymentMethodStats) {
                addBarRow(binding.llPaymentMethods, e.getKey(),
                        e.getValue() + " transactions",
                        (float) e.getValue() / maxPay, payColors[ci++ % payColors.length]);
            }
        } else {
            addEmptyRow(binding.llPaymentMethods, "No data");
        }

        // Employee Performance
        boolean showEmployeeSection = viewModel.getViewMode().equals("store");
        View empParent = (View) binding.llEmployeePerformance.getParent();
        if (empParent != null) empParent.setVisibility(showEmployeeSection ? View.VISIBLE : View.GONE);
        if (showEmployeeSection) {
            binding.llEmployeePerformance.removeAllViews();
            if (data.employeePerformance != null && !data.employeePerformance.isEmpty()) {
                BigDecimal maxEmp = data.employeePerformance.get(0).getValue();
                if (maxEmp.compareTo(BigDecimal.ZERO) == 0) maxEmp = BigDecimal.ONE;
                for (Map.Entry<String, BigDecimal> e : data.employeePerformance) {
                    addBarRow(binding.llEmployeePerformance, e.getKey(),
                            "$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
                            e.getValue().floatValue() / maxEmp.floatValue(), "#1a759f");
                }
            } else {
                addEmptyRow(binding.llEmployeePerformance, "No data");
            }
        }

        // Daily Revenue
        binding.tvDailyRevenueTitle.setText(data.dailyRevenueTitle);
        binding.llDailyRevenue.removeAllViews();
        if (data.dailyRevenue != null && !data.dailyRevenue.isEmpty()) {
            BigDecimal maxDaily = data.dailyRevenue.stream()
                    .map(Map.Entry::getValue).max(BigDecimal::compareTo).orElse(BigDecimal.ONE);
            if (maxDaily.compareTo(BigDecimal.ZERO) == 0) maxDaily = BigDecimal.ONE;
            for (Map.Entry<String, BigDecimal> e : data.dailyRevenue) {
                String label = e.getKey().length() >= 10 ? e.getKey().substring(5) : e.getKey();
                addBarRow(binding.llDailyRevenue, label,
                        "$" + e.getValue().setScale(2, RoundingMode.HALF_UP),
                        e.getValue().floatValue() / maxDaily.floatValue(), "#ff6b35");
            }
        } else {
            addEmptyRow(binding.llDailyRevenue, "No data");
        }
    }

    // Chart Helpers

    private void addBarRow(LinearLayout parent, String label, String value, float ratio, String color) {
        if (getContext() == null) return;
        LinearLayout row = new LinearLayout(getContext());
        row.setOrientation(LinearLayout.VERTICAL);
        row.setPadding(0, 6, 0, 6);

        LinearLayout labelRow = new LinearLayout(getContext());
        labelRow.setOrientation(LinearLayout.HORIZONTAL);

        TextView tvLabel = new TextView(getContext());
        tvLabel.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f));
        tvLabel.setText(label);
        tvLabel.setTextColor(Color.parseColor("#444441"));
        tvLabel.setTextSize(13f);

        TextView tvValue = new TextView(getContext());
        tvValue.setText(value);
        tvValue.setTextColor(Color.parseColor("#444441"));
        tvValue.setTextSize(13f);
        tvValue.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);

        labelRow.addView(tvLabel);
        labelRow.addView(tvValue);

        LinearLayout barBg = new LinearLayout(getContext());
        LinearLayout.LayoutParams bgParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 12);
        bgParams.setMargins(0, 4, 0, 0);
        barBg.setLayoutParams(bgParams);
        barBg.setBackgroundColor(Color.parseColor("#EEEEEE"));

        float safeRatio = Math.max(0f, Math.min(1f, ratio));
        View barFill = new View(getContext());
        barFill.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, safeRatio));
        barFill.setBackgroundColor(Color.parseColor(color));
        barBg.addView(barFill);

        View spacer = new View(getContext());
        spacer.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f - safeRatio));
        barBg.addView(spacer);

        row.addView(labelRow);
        row.addView(barBg);
        parent.addView(row);
    }

    private void addEmptyRow(LinearLayout parent, String message) {
        if (getContext() == null) return;
        TextView tv = new TextView(getContext());
        tv.setText(message);
        tv.setTextColor(Color.parseColor("#888780"));
        tv.setTextSize(13f);
        parent.addView(tv);
    }

    private void showError(String msg) {
        if (getContext() == null || binding == null) return;
        binding.tvTotalRevenue.setText("Error");
        binding.tvTotalTransactions.setText("—");
        binding.tvAvgTransaction.setText("—");
        binding.tvTotalItems.setText("—");
        Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
    }
}
