package com.streamplayer;

import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.net.VpnService;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

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

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private RecyclerView sectionList;
    private RecyclerView contentList;
    private ProgressBar loadingIndicator;
    private TextView messageView;
    private TextView contentTitle;
    private Button refreshButton;
    private Button vpnButton;

    private ChannelAdapter channelAdapter;
    private EventAdapter eventAdapter;
    private EventRepository eventRepository;
    private SectionAdapter sectionAdapter;
    private GridLayoutManager channelLayoutManager;
    private LinearLayoutManager eventLayoutManager;
    private final List<EventItem> cachedEvents = new ArrayList<>();
    private List<SectionEntry> sections;
    private SectionEntry currentSection;
    private UpdateManager updateManager;
    private AlertDialog updateDialog;
    private AlertDialog blockedDialog;
    private DeviceRegistry deviceRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sectionList = findViewById(R.id.section_list);
        contentList = findViewById(R.id.content_list);
        loadingIndicator = findViewById(R.id.loading_indicator);
        messageView = findViewById(R.id.message_view);
        contentTitle = findViewById(R.id.content_title);
        refreshButton = findViewById(R.id.refresh_button);
        vpnButton = findViewById(R.id.vpn_button);

        VpnManager.init(this);
        updateVpnButton();

        vpnButton.setOnClickListener(v -> toggleVpn());

        refreshButton.setOnClickListener(v -> {
            loadEvents(true);
            Toast.makeText(this, "Actualizando eventos...", Toast.LENGTH_SHORT).show();
        });

        channelAdapter = new ChannelAdapter(
                channel -> openPlayer(channel.getName(), channel.getPageUrl()));
        eventAdapter = new EventAdapter(event -> openPlayer(event.getTitle(), event.getPageUrl()));
        eventRepository = new EventRepository();
        channelLayoutManager = new GridLayoutManager(this, getSpanCount());
        eventLayoutManager = new LinearLayoutManager(this) {
            @Override
            public View onInterceptFocusSearch(View focused, int direction) {
                if (direction == View.FOCUS_DOWN) {
                    int pos = getPosition(focused);
                    if (pos == getItemCount() - 1) {
                        return focused;
                    }
                }
                return super.onInterceptFocusSearch(focused, direction);
            }
        };

        sections = buildSections();
        sectionList.setLayoutManager(new LinearLayoutManager(this));
        sectionAdapter = new SectionAdapter(getSectionTitles(), this::selectSection);
        sectionList.setAdapter(sectionAdapter);

        selectSection(0);

        updateManager = new UpdateManager(this);
        updateManager.checkForUpdates(new UpdateManager.UpdateCallback() {
            @Override
            public void onUpdateAvailable(UpdateManager.UpdateInfo info) {
                handleUpdateInfo(info);
            }

            @Override
            public void onUpToDate() {
                // Nothing to do.
            }

            @Override
            public void onError(String message) {
                Toast.makeText(MainActivity.this,
                        getString(R.string.update_error_checking, message),
                        Toast.LENGTH_SHORT).show();
            }
        });

        deviceRegistry = new DeviceRegistry(this);
        deviceRegistry.syncDevice(new DeviceRegistry.Callback() {
            @Override
            public void onAllowed() {
                // Device authorized, continue normally.
            }

            @Override
            public void onBlocked(String reason, String tokenPart) {
                showBlockedDialog(reason, tokenPart);
            }

            @Override
            public void onError(String message) {
                if (!TextUtils.isEmpty(message)) {
                    Toast.makeText(MainActivity.this,
                            getString(R.string.device_registry_error, message),
                            Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (updateManager != null) {
            updateManager.resumePendingInstall(this);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (updateDialog != null && updateDialog.isShowing()) {
            updateDialog.dismiss();
        }
        if (blockedDialog != null && blockedDialog.isShowing()) {
            blockedDialog.dismiss();
        }
        if (updateManager != null) {
            updateManager.release();
        }
        if (deviceRegistry != null) {
            deviceRegistry.release();
        }
    }

    private void selectSection(int index) {
        if (sections == null || sections.isEmpty()) {
            return;
        }
        if (index < 0 || index >= sections.size()) {
            index = 0;
        }
        sectionAdapter.setSelectedIndex(index);
        currentSection = sections.get(index);
        if (currentSection.type == SectionEntry.Type.EVENTS) {
            showEvents();
        } else {
            showChannels(currentSection);
        }
    }

    private void showChannels(SectionEntry section) {
        contentTitle.setText(section.title);
        refreshButton.setVisibility(View.GONE);
        contentList.setLayoutManager(channelLayoutManager);
        contentList.setAdapter(channelAdapter);
        // Clear any scroll listeners from Events section
        contentList.clearOnScrollListeners();
        loadingIndicator.setVisibility(View.GONE);
        channelAdapter.submitList(section.channels);
        if (section.channels.isEmpty()) {
            messageView.setVisibility(View.VISIBLE);
            messageView.setText(R.string.message_no_channels);
        } else {
            messageView.setVisibility(View.GONE);
            contentList.post(() -> contentList.scrollToPosition(0));
        }
    }

    private void showEvents() {
        contentTitle.setText(currentSection != null ? currentSection.title : getString(R.string.section_events));
        refreshButton.setVisibility(View.VISIBLE);
        contentList.setLayoutManager(eventLayoutManager);
        contentList.setAdapter(eventAdapter);
        // Clear existing listeners
        contentList.clearOnScrollListeners();

        if (cachedEvents.isEmpty()) {
            loadEvents(false);
        } else {
            displayEvents();
        }
    }

    private void loadEvents(boolean forceRefresh) {
        loadingIndicator.setVisibility(View.VISIBLE);
        messageView.setVisibility(View.GONE);
        eventRepository.loadEvents(this, forceRefresh, new EventRepository.Callback() {
            @Override
            public void onSuccess(List<EventItem> events) {
                runOnUiThread(() -> {
                    cachedEvents.clear();
                    cachedEvents.addAll(events);
                    if (currentSection != null && currentSection.type == SectionEntry.Type.EVENTS) {
                        displayEvents();
                    } else {
                        loadingIndicator.setVisibility(View.GONE);
                    }
                });
            }

            @Override
            public void onError(String message) {
                runOnUiThread(() -> {
                    loadingIndicator.setVisibility(View.GONE);
                    messageView.setVisibility(View.VISIBLE);
                    messageView.setText(getString(R.string.message_events_error, message));
                });
            }
        });
    }

    private void displayEvents() {
        loadingIndicator.setVisibility(View.GONE);
        if (cachedEvents.isEmpty()) {
            messageView.setVisibility(View.VISIBLE);
            messageView.setText(R.string.message_no_events);
            eventAdapter.submitList(new ArrayList<>());
        } else {
            messageView.setVisibility(View.GONE);
            eventAdapter.submitList(new ArrayList<>(cachedEvents));
        }
    }

    private void openPlayer(String name, String pageUrl) {
        Intent intent = new Intent(MainActivity.this, PlayerActivity.class);
        intent.putExtra(PlayerActivity.EXTRA_CHANNEL_NAME, name);
        intent.putExtra(PlayerActivity.EXTRA_CHANNEL_URL, pageUrl);
        startActivity(intent);
    }

    private void handleUpdateInfo(UpdateManager.UpdateInfo info) {
        if (info == null) {
            return;
        }
        boolean forceUpdate = info.isMandatory(BuildConfig.VERSION_CODE);
        showUpdateDialog(info, forceUpdate);
    }

    private void showUpdateDialog(UpdateManager.UpdateInfo info, boolean mandatory) {
        if (isFinishing()) {
            return;
        }
        if (updateDialog != null && updateDialog.isShowing()) {
            updateDialog.dismiss();
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.ThemeOverlay_StreamPlayer_AlertDialog)
                .setTitle(mandatory ? R.string.update_required_title : R.string.update_available_title)
                .setMessage(buildUpdateMessage(info))
                .setPositiveButton(R.string.update_action_download,
                        (dialog, which) -> updateManager.downloadUpdate(MainActivity.this, info))
                .setNeutralButton(R.string.update_action_view_release,
                        (dialog, which) -> openReleasePage(info));
        if (mandatory) {
            builder.setCancelable(false);
            builder.setNegativeButton(R.string.update_action_close_app,
                    (dialog, which) -> finish());
        } else {
            builder.setNegativeButton(R.string.update_action_later, null);
        }
        updateDialog = builder.show();
    }

    private CharSequence buildUpdateMessage(UpdateManager.UpdateInfo info) {
        StringBuilder builder = new StringBuilder();
        builder.append(getString(R.string.update_current_version,
                BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
        builder.append('\n');
        builder.append(getString(R.string.update_latest_version,
                info.versionName, info.versionCode));
        if (info.minSupportedVersionCode > 0) {
            builder.append('\n').append(getString(R.string.update_min_supported,
                    info.minSupportedVersionCode));
        }
        String size = info.formatSize(this);
        if (!size.isEmpty()) {
            builder.append('\n').append(getString(R.string.update_download_size, size));
        }
        if (info.downloadCount > 0) {
            builder.append('\n').append(getString(R.string.update_downloads,
                    info.downloadCount));
        }
        if (!info.releaseNotes.isEmpty()) {
            builder.append("\n\n");
            builder.append(getString(R.string.update_release_notes_title));
            builder.append('\n');
            builder.append(info.getReleaseNotesPreview());
        }
        if (!info.isMandatory(BuildConfig.VERSION_CODE)) {
            builder.append("\n\n");
            builder.append(getString(R.string.update_optional_hint));
        }
        return builder.toString();
    }

    private void openReleasePage(UpdateManager.UpdateInfo info) {
        String url = info.releasePageUrl;
        if (url == null || url.isEmpty()) {
            url = info.downloadUrl;
        }
        if (url == null || url.isEmpty()) {
            Toast.makeText(this, R.string.update_error_missing_url, Toast.LENGTH_SHORT).show();
            return;
        }
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        try {
            startActivity(intent);
        } catch (Exception e) {
            Toast.makeText(this, R.string.update_error_open_release, Toast.LENGTH_SHORT).show();
        }
    }

    private void showBlockedDialog(String reason, String tokenPart) {
        if (isFinishing()) {
            return;
        }
        String finalReason = TextUtils.isEmpty(reason)
                ? getString(R.string.device_blocked_default_reason)
                : reason;
        if (blockedDialog != null && blockedDialog.isShowing()) {
            blockedDialog.dismiss();
        }
        View dialogView = getLayoutInflater().inflate(R.layout.dialog_blocked, null);
        TextView messageText = dialogView.findViewById(R.id.blocked_message_text);
        View tokenContainer = dialogView.findViewById(R.id.blocked_token_container);
        TextView tokenValue = dialogView.findViewById(R.id.blocked_token_value);
        messageText.setText(getString(R.string.device_blocked_message, finalReason));
        boolean hasToken = !TextUtils.isEmpty(tokenPart);
        if (hasToken) {
            tokenContainer.setVisibility(View.VISIBLE);
            tokenValue.setText(tokenPart);
            tokenValue.setOnClickListener(v -> copyTokenToClipboard(tokenPart));
        } else {
            tokenContainer.setVisibility(View.GONE);
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.ThemeOverlay_StreamPlayer_AlertDialog)
                .setTitle(R.string.device_blocked_title)
                .setView(dialogView)
                .setCancelable(false)
                .setPositiveButton(R.string.device_blocked_close,
                        (dialog, which) -> finish());
        if (hasToken) {
            builder.setNeutralButton(R.string.device_blocked_copy_token,
                    (dialog, which) -> copyTokenToClipboard(tokenPart));
        }
        blockedDialog = builder.create();
        blockedDialog.show();
    }

    private void copyTokenToClipboard(String tokenPart) {
        ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        if (clipboard == null) {
            Toast.makeText(this, R.string.device_blocked_copy_error, Toast.LENGTH_SHORT).show();
            return;
        }
        ClipData data = ClipData.newPlainText("token", tokenPart);
        clipboard.setPrimaryClip(data);
        Toast.makeText(this, R.string.device_blocked_copy_success, Toast.LENGTH_SHORT).show();
    }

    private void toggleVpn() {
        VpnManager vpnManager = VpnManager.getInstance();
        if (vpnManager.isConnected()) {
            vpnManager.disconnect();
            Toast.makeText(this, R.string.vpn_disconnected, Toast.LENGTH_SHORT).show();
            updateVpnButton();
        } else {
            // Check if VPN permission is needed
            try {
                Intent prepareIntent = com.wireguard.android.backend.GoBackend.VpnService.prepare(this);
                if (prepareIntent != null) {
                    // Need permission
                    try {
                        startActivityForResult(prepareIntent, 1001);
                    } catch (Exception e) {
                        Toast.makeText(this, "Error: " + e.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                    return;
                }
            } catch (Exception e) {
                Log.e(TAG, "Error checking VPN permission: " + e.getMessage());
            }
            
            vpnButton.setText(R.string.vpn_connecting);
            vpnButton.setEnabled(false);
            new Thread(() -> {
                boolean success = vpnManager.connect();
                runOnUiThread(() -> {
                    vpnButton.setEnabled(true);
                    if (success) {
                        Toast.makeText(this, R.string.vpn_connected, Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(this, R.string.vpn_error, Toast.LENGTH_SHORT).show();
                    }
                    updateVpnButton();
                });
            }).start();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 1001 && resultCode == RESULT_OK) {
            // Permission granted, try to connect
            toggleVpn();
        }
    }

    private void updateVpnButton() {
        VpnManager vpnManager = VpnManager.getInstance();
        if (vpnManager.isConnected()) {
            vpnButton.setText(R.string.vpn_disconnect);
            vpnButton.setSelected(true);
        } else {
            vpnButton.setText(R.string.vpn_connect);
            vpnButton.setSelected(false);
        }
    }

    private int getSpanCount() {
        return getResources().getInteger(R.integer.channel_grid_span);
    }

    private List<SectionEntry> buildSections() {
        List<SectionEntry> list = new ArrayList<>();
        list.add(SectionEntry.events(getString(R.string.section_events)));

        Map<String, List<StreamChannel>> grouped = new HashMap<>();
        List<StreamChannel> allChannels = ChannelRepository.getChannels();
        for (StreamChannel channel : allChannels) {
            String key = deriveGroupName(channel.getName());
            grouped.computeIfAbsent(key, k -> new ArrayList<>()).add(channel);
        }

        List<StreamChannel> espnChannels = grouped.remove("ESPN");
        if (espnChannels != null && !espnChannels.isEmpty()) {
            list.add(SectionEntry.channels("ESPN", espnChannels));
        }

        List<String> remaining = new ArrayList<>(grouped.keySet());
        Collections.sort(remaining, String.CASE_INSENSITIVE_ORDER);
        for (String key : remaining) {
            List<StreamChannel> channels = grouped.get(key);
            if (channels == null || channels.isEmpty()) {
                continue;
            }
            list.add(SectionEntry.channels(key, channels));
        }

        list.add(SectionEntry.channels(getString(R.string.section_all_channels), allChannels));
        return list;
    }

    private List<String> getSectionTitles() {
        List<String> titles = new ArrayList<>();
        for (SectionEntry entry : sections) {
            titles.add(entry.title);
        }
        return titles;
    }

    private String deriveGroupName(String name) {
        if (name == null) {
            return getString(R.string.section_all_channels);
        }
        String upper = name.toUpperCase(Locale.US);
        if (upper.startsWith("ESPN")) {
            return "ESPN";
        } else if (upper.contains("FOX SPORTS")) {
            return "Fox Sports";
        } else if (upper.contains("FOX")) {
            return "Fox";
        } else if (upper.contains("TNT")) {
            return "TNT";
        } else if (upper.contains("DAZN")) {
            return "DAZN";
        } else if (upper.contains("TUDN")) {
            return "TUDN";
        } else if (upper.contains("TYC")) {
            return "TyC";
        } else if (upper.contains("GOL")) {
            return "Gol";
        }
        int spaceIndex = upper.indexOf(' ');
        return spaceIndex > 0 ? upper.substring(0, spaceIndex) : upper;
    }

    private static class SectionEntry {
        enum Type { EVENTS, CHANNELS }

        final String title;
        final Type type;
        final List<StreamChannel> channels;

        private SectionEntry(String title, Type type, List<StreamChannel> channels) {
            this.title = title;
            this.type = type;
            this.channels = channels == null ? new ArrayList<>() : new ArrayList<>(channels);
        }

        static SectionEntry events(String title) {
            return new SectionEntry(title, Type.EVENTS, null);
        }

        static SectionEntry channels(String title, List<StreamChannel> channels) {
            return new SectionEntry(title, Type.CHANNELS, channels);
        }
    }
}
