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 android.widget.Toast;
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 com.google.gson.JsonElement;
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;

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;

    private ActivityResultLauncher<String> requestPermissionLauncher;

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

    @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()));
        swipeRefreshLayout.setOnRefreshListener(this::refreshData);

        refreshData();
    }

    private void refreshData() {
        if (activeNetworkCalls > 0) return;
        activeNetworkCalls = 3;
        if (mainProgressBar != null) mainProgressBar.setVisibility(View.VISIBLE);

        fetchCalendarData();
        fetchNewsData();
        fetchTaskData();
    }

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

        new Thread(() -> {
            List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext(), true);
            new Handler(Looper.getMainLooper()).post(() -> {
                RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
                    @Override
                    public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
                        List<CalendarEvent> apiEvents = new ArrayList<>();
                        if (response.isSuccessful() && response.body() != null) {
                            apiEvents = response.body();
                            CacheManager.saveCalendarEvents(getContext(), apiEvents);
                        } else {
                            apiEvents = CacheManager.getCachedCalendarEvents(getContext());
                        }
                        for (CalendarEvent e : apiEvents) CalendarManager.formatEventForUI(e);
                        currentEvents = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
                        checkLoadingComplete();
                    }
                    @Override
                    public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
                        List<CalendarEvent> cached = CacheManager.getCachedCalendarEvents(getContext());
                        for (CalendarEvent e : cached) CalendarManager.formatEventForUI(e);
                        currentEvents = CalendarManager.mergeAndSort(cached, deviceEvents);
                        checkLoadingComplete();
                    }
                });
            });
        }).start();
    }

    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);
                } else {
                    currentNews = CacheManager.getCachedNewsPosts(getContext());
                }
                formatNewsDates(currentNews);
                checkLoadingComplete();
            }
            @Override
            public void onFailure(Call<List<WpPost>> call, Throwable t) {
                currentNews = CacheManager.getCachedNewsPosts(getContext());
                formatNewsDates(currentNews);
                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);
                } else {
                    currentTasks = CacheManager.getTasks(getContext());
                }
                checkLoadingComplete();
            }
            @Override
            public void onFailure(Call<List<TaskItem>> call, Throwable t) {
                currentTasks = CacheManager.getTasks(getContext());
                checkLoadingComplete();
            }
        });
    }

    private void formatNewsDates(List<WpPost> posts) {
        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 {
                Date date = rawFormat.parse(post.date);
                post.date = targetFormat.format(date);
            } catch (Exception ignored) {}
        }
    }

    private void checkLoadingComplete() {
        activeNetworkCalls--;
        if (activeNetworkCalls <= 0) {
            activeNetworkCalls = 0;
            if (mainProgressBar != null) mainProgressBar.setVisibility(View.GONE);
            swipeRefreshLayout.setRefreshing(false);
            buildAndDisplayList();
        }
    }

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

        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;
        for (CalendarEvent e : currentEvents) {
            if (e.getRawDate() != null && e.getRawDate().compareTo(today) >= 0) {
                items.add(e);
                calCount++;
            }
            if (calCount >= 3) break;
        }

        items.add(new HomeAdapter.SectionTitleItem("Mine oppgaver", HomeAdapter.SectionTitleItem.TYPE_TASKS));
        List<TaskItem> myActiveTasks = new ArrayList<>();
        for (TaskItem t : currentTasks) {
            if (t.isUserParticipant(myEmail) && !t.getParticipantStatus(myEmail) && !t.isFullyCompleted()) {
                myActiveTasks.add(t);
            }
        }

        if (myActiveTasks.isEmpty()) {
            items.add(new HomeAdapter.EmptyTasksItem());
        } else {
            Collections.sort(myActiveTasks, (t1, t2) -> Long.compare(t1.getDueDate(), t2.getDueDate()));
            for (int i = 0; i < Math.min(myActiveTasks.size(), 3); i++) {
                items.add(myActiveTasks.get(i));
            }
        }

        items.add(new HomeAdapter.SectionTitleItem("Siste nytt", HomeAdapter.SectionTitleItem.TYPE_NEWS));
        items.addAll(currentNews);

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

    @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(this::refreshData);
        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) {}
        });
    }
}