package com.kbs.kbsintranett;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import com.google.gson.JsonElement;

public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickListener {

    private RecyclerView recyclerView;
    private HomeAdapter adapter;
    private ProgressBar mainProgressBar;
    private SwipeRefreshLayout swipeRefreshLayout;

    private List<CalendarEvent> currentEvents = new ArrayList<>();
    private List<WpPost> currentNews = new ArrayList<>();
    private List<TaskItem> currentTasks = new ArrayList<>();

    private int activeNetworkCalls = 0;
    // Cache lever i 60 minutter. PUSH vil ugyldiggjøre den før tiden ved behov.
    private static final int CACHE_TTL_MINUTES = 60;

    private Handler timeoutHandler = new Handler(Looper.getMainLooper());
    private Runnable timeoutRunnable = this::forceStopLoading;

    private ActivityResultLauncher<String> requestPermissionLauncher;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestPermissionLauncher = registerForActivityResult(
                new ActivityResultContracts.RequestPermission(),
                isGranted -> refreshData(true)
        );
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_home, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mainProgressBar = view.findViewById(R.id.main_loading_spinner);
        swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_home);
        recyclerView = view.findViewById(R.id.main_recycler_view);

        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));

        // Ved manuell swipe: Tving nettverksoppdatering
        swipeRefreshLayout.setOnRefreshListener(() -> refreshData(true));

        // Ved oppstart: Bruk cache (false = ikke tving nettverk)
        refreshData(false);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        timeoutHandler.removeCallbacks(timeoutRunnable);
    }

    private void refreshData(boolean forceNetwork) {
        // 1. Last cache i bakgrunnen
        new Thread(() -> {
            if (getContext() == null) return;

            // Hent data fra disk
            List<CalendarEvent> cachedApiEvents = CacheManager.getCachedCalendarEvents(getContext());
            List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext(), true);

            for (CalendarEvent e : cachedApiEvents) CalendarManager.formatEventForUI(e);
            List<CalendarEvent> mergedEvents = CalendarManager.mergeAndSort(cachedApiEvents, deviceEvents);

            List<WpPost> cachedNews = CacheManager.getCachedNewsPosts(getContext());
            formatNewsDates(cachedNews);

            List<TaskItem> cachedTasks = CacheManager.getTasks(getContext());

            // 2. Oppdater UI på hovedtråden
            new Handler(Looper.getMainLooper()).post(() -> {
                if (!isAdded()) return;

                // Oppdater variablene
                currentEvents = mergedEvents;
                currentNews = cachedNews;
                currentTasks = cachedTasks;

                // Vis dataene vi fant umiddelbart (fjerner spinner hvis den var der)
                buildAndDisplayList();

                // 3. Vurder om vi skal hente nytt fra nettet
                boolean cacheValidCal = CacheManager.isCacheValid(getContext(), "calendar", CACHE_TTL_MINUTES);
                boolean cacheValidNews = CacheManager.isCacheValid(getContext(), "news", CACHE_TTL_MINUTES);
                boolean cacheValidTasks = CacheManager.isCacheValid(getContext(), "tasks", CACHE_TTL_MINUTES);

                // Vi henter KUN hvis brukeren swiper (force) ELLER cachen er utgått på dato.
                // Vi henter IKKE bare fordi listene er tomme (da stoler vi på at cachen er korrekt tom).
                boolean needNetwork = forceNetwork || !cacheValidCal || !cacheValidNews || !cacheValidTasks;

                if (needNetwork) {
                    // Vis spinner KUN hvis det er helt tomt fra før, eller ved manuell swipe
                    boolean isEverythingEmpty = currentNews.isEmpty() && currentTasks.isEmpty() && currentEvents.isEmpty();

                    if (isEverythingEmpty && mainProgressBar != null) {
                        mainProgressBar.setVisibility(View.VISIBLE);
                    } else if (forceNetwork && swipeRefreshLayout != null) {
                        swipeRefreshLayout.setRefreshing(true);
                    }
                    // Ellers: Silent update (ingen spinner, men vi henter i bakgrunnen)

                    activeNetworkCalls = 3;
                    timeoutHandler.removeCallbacks(timeoutRunnable);
                    timeoutHandler.postDelayed(timeoutRunnable, 10000); // 10 sek timeout

                    fetchCalendarData();
                    fetchNewsData();
                    fetchTaskData();
                } else {
                    // Cachen er god nok! Skjul evt spinnere.
                    stopLoaders();
                }
            });
        }).start();
    }

    private void stopLoaders() {
        if (mainProgressBar != null) mainProgressBar.setVisibility(View.GONE);
        if (swipeRefreshLayout != null) swipeRefreshLayout.setRefreshing(false);
    }

    private void forceStopLoading() {
        if (activeNetworkCalls > 0) {
            activeNetworkCalls = 0;
            stopLoaders();
            buildAndDisplayList();
        }
    }

    private void fetchCalendarData() {
        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
            requestPermissionLauncher.launch(Manifest.permission.READ_CALENDAR);
            checkLoadingComplete();
            return;
        }

        RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
            @Override
            public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    List<CalendarEvent> apiEvents = response.body();
                    CacheManager.saveCalendarEvents(getContext(), apiEvents);

                    new Thread(() -> {
                        List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext(), true);
                        for (CalendarEvent e : apiEvents) CalendarManager.formatEventForUI(e);
                        List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
                        new Handler(Looper.getMainLooper()).post(() -> {
                            currentEvents = merged;
                            checkLoadingComplete();
                        });
                    }).start();
                } else {
                    checkLoadingComplete();
                }
            }
            @Override
            public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
                checkLoadingComplete();
            }
        });
    }

    private void fetchNewsData() {
        RetrofitClient.getApiService().getPosts().enqueue(new Callback<List<WpPost>>() {
            @Override
            public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    currentNews = response.body();
                    CacheManager.saveNewsPosts(getContext(), currentNews);
                    formatNewsDates(currentNews);
                }
                checkLoadingComplete();
            }
            @Override
            public void onFailure(Call<List<WpPost>> call, Throwable t) {
                checkLoadingComplete();
            }
        });
    }

    private void fetchTaskData() {
        RetrofitClient.getApiService().getTasks().enqueue(new Callback<List<TaskItem>>() {
            @Override
            public void onResponse(Call<List<TaskItem>> call, Response<List<TaskItem>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    currentTasks = response.body();
                    CacheManager.saveTasks(getContext(), currentTasks);
                }
                checkLoadingComplete();
            }
            @Override
            public void onFailure(Call<List<TaskItem>> call, Throwable t) {
                checkLoadingComplete();
            }
        });
    }

    private void formatNewsDates(List<WpPost> posts) {
        if (posts == null) return;
        SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
        SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
        for (WpPost post : posts) {
            try {
                if (post.date != null && post.date.contains("T")) {
                    Date date = rawFormat.parse(post.date);
                    post.date = targetFormat.format(date);
                }
            } catch (Exception ignored) {}
        }
    }

    private synchronized void checkLoadingComplete() {
        activeNetworkCalls--;
        // Oppdater visningen fortløpende så snart data kommer inn
        buildAndDisplayList();

        if (activeNetworkCalls <= 0) {
            activeNetworkCalls = 0;
            timeoutHandler.removeCallbacks(timeoutRunnable);
            stopLoaders();
        }
    }

    private void buildAndDisplayList() {
        if (!isAdded()) return;

        List<Object> items = new ArrayList<>();
        String myEmail = UserManager.getInstance().getUserEmail();

        // 1. KALENDER
        items.add(new HomeAdapter.SectionTitleItem("Kommende hendelser", HomeAdapter.SectionTitleItem.TYPE_CALENDAR));
        String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
        int calCount = 0;
        if (currentEvents != null) {
            for (CalendarEvent e : currentEvents) {
                if (e.getRawDate() != null && e.getRawDate().compareTo(today) >= 0) {
                    items.add(e);
                    calCount++;
                }
                if (calCount >= 3) break;
            }
        }

        // 2. OPPGAVER
        items.add(new HomeAdapter.SectionTitleItem("Mine oppgaver", HomeAdapter.SectionTitleItem.TYPE_TASKS));
        List<TaskItem> myActiveTasks = new ArrayList<>();
        if (currentTasks != null) {
            for (TaskItem t : currentTasks) {
                // Vis oppgaver jeg er deltaker i, som ikke er fullført av meg, og ikke helt lukket
                if (t.isUserParticipant(myEmail) && !t.getParticipantStatus(myEmail) && !t.isFullyCompleted()) {
                    myActiveTasks.add(t);
                }
            }
        }

        if (myActiveTasks.isEmpty()) {
            items.add(new HomeAdapter.EmptyTasksItem());
        } else {
            // Sortering: Dato (stigende), deretter de uten dato (alfabetisk)
            Collections.sort(myActiveTasks, (t1, t2) -> {
                boolean t1HasDate = t1.getDueDate() > 0;
                boolean t2HasDate = t2.getDueDate() > 0;

                if (t1HasDate && !t2HasDate) return -1;
                if (!t1HasDate && t2HasDate) return 1;
                if (!t1HasDate && !t2HasDate) return t1.getTitle().compareToIgnoreCase(t2.getTitle());

                return Long.compare(t1.getDueDate(), t2.getDueDate());
            });

            for (int i = 0; i < Math.min(myActiveTasks.size(), 3); i++) {
                items.add(myActiveTasks.get(i));
            }
        }

        // 3. NYHETER
        items.add(new HomeAdapter.SectionTitleItem("Siste nytt", HomeAdapter.SectionTitleItem.TYPE_NEWS));
        if (currentNews != null) {
            items.addAll(currentNews);
        }

        adapter = new HomeAdapter(items, this);
        recyclerView.setAdapter(adapter);
    }

    // --- NAVIGASJON & KLIKK ---

    @Override public void onCreateEventClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_create_event); }
    @Override public void onViewAllCalendarClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_calendar_full); }
    @Override public void onViewAllNewsClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_news_full); }
    @Override public void onViewAllTasksClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_tasks); }

    @Override public void onCalendarItemClick(CalendarEvent event) {
        CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
        sheet.setOnEventChangeListener(() -> refreshData(true));
        sheet.show(getParentFragmentManager(), "CalendarDetails");
    }

    @Override public void onNewsItemClick(WpPost post) {
        Bundle bundle = new Bundle();
        bundle.putSerializable("post_data", post);
        Navigation.findNavController(getView()).navigate(R.id.navigation_news_detail, bundle);
    }

    @Override public void onTaskItemClick(TaskItem task) {
        TaskDetailsBottomSheet sheet = new TaskDetailsBottomSheet(task, new TaskDetailsBottomSheet.OnTaskChangeListener() {
            @Override public void onTaskChanged() { saveAndSyncTasks(); }
            @Override public void onTaskDeleted(TaskItem taskToDelete) {
                currentTasks.remove(taskToDelete);
                saveAndSyncTasks();
            }
            @Override public void onEditRequested(TaskItem taskToEdit) {
                AddTaskBottomSheet editDialog = new AddTaskBottomSheet();
                editDialog.setTaskToEdit(taskToEdit);
                editDialog.setOnTaskAddedListener(new AddTaskBottomSheet.OnTaskAddedListener() {
                    @Override public void onTaskAdded(TaskItem task) {}
                    @Override public void onTaskUpdated(TaskItem task) {
                        saveAndSyncTasks();
                    }
                });
                editDialog.show(getChildFragmentManager(), "EditTask");
            }
        });
        sheet.show(getChildFragmentManager(), "TaskDetails");
    }

    @Override public void onTaskStatusChanged(TaskItem task, boolean isDone) {
        String myEmail = UserManager.getInstance().getUserEmail();
        task.setParticipantStatus(myEmail, isDone);
        if (task.getCreatedByEmail().equalsIgnoreCase(myEmail) && isDone) {
            task.setFullyCompleted(true);
        }
        saveAndSyncTasks();
    }

    private void saveAndSyncTasks() {
        CacheManager.saveTasks(getContext(), currentTasks);
        buildAndDisplayList();
        RetrofitClient.getApiService().syncTasks(currentTasks).enqueue(new Callback<JsonElement>() {
            @Override public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {}
            @Override public void onFailure(Call<JsonElement> call, Throwable t) {}
        });
    }
}