package com.bibliadiaria.app;

import android.app.Activity;
import android.app.AlertDialog;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Switch;
import android.widget.TextView;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SettingsActivity extends Activity {
    // Light mode colors
    private static final int COLOR_BG_LIGHT = Color.rgb(247, 248, 246);
    private static final int COLOR_CARD_LIGHT = Color.WHITE;
    private static final int COLOR_INK_LIGHT = Color.rgb(25, 31, 31);
    private static final int COLOR_MUTED_LIGHT = Color.rgb(91, 99, 98);
    private static final int COLOR_STROKE_LIGHT = Color.rgb(219, 226, 222);
    private static final int COLOR_CARD_STROKE_LIGHT = Color.rgb(229, 232, 230);

    // Dark mode colors
    private static final int COLOR_BG_DARK = Color.rgb(26, 28, 30);
    private static final int COLOR_CARD_DARK = Color.rgb(38, 41, 44);
    private static final int COLOR_INK_DARK = Color.rgb(224, 226, 219);
    private static final int COLOR_MUTED_DARK = Color.rgb(158, 163, 160);
    private static final int COLOR_STROKE_DARK = Color.rgb(48, 52, 55);
    private static final int COLOR_CARD_STROKE_DARK = Color.rgb(58, 62, 65);

    private static final int COLOR_ACCENT = Color.rgb(0, 107, 90);
    private static final int COLOR_WARM = Color.rgb(217, 75, 61);

    private ExecutorService executor;
    private TextView statusText;
    private TextView installedVersionText;
    private TextView checkButton;
    private TextView downloadButton;
    private TextView voiceSubtitleText;
    private TextView voiceButton;
    private UpdateManager.UpdateInfo latestInfo;
    private boolean isEnglish;
    private boolean isDarkMode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        isEnglish = UpdateManager.isEnglish(this);
        isDarkMode = UpdateManager.isDarkMode(this);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setStatusBarColor(bg());
            getWindow().setNavigationBarColor(bg());
        }

        executor = Executors.newSingleThreadExecutor();
        setContentView(createScreen());
        updateInstalledVersionText();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (executor != null) {
            executor.shutdownNow();
        }
    }

    private int bg() { return isDarkMode ? COLOR_BG_DARK : COLOR_BG_LIGHT; }
    private int card() { return isDarkMode ? COLOR_CARD_DARK : COLOR_CARD_LIGHT; }
    private int ink() { return isDarkMode ? COLOR_INK_DARK : COLOR_INK_LIGHT; }
    private int muted() { return isDarkMode ? COLOR_MUTED_DARK : COLOR_MUTED_LIGHT; }
    private int stroke() { return isDarkMode ? COLOR_STROKE_DARK : COLOR_STROKE_LIGHT; }
    private int cardStroke() { return isDarkMode ? COLOR_CARD_STROKE_DARK : COLOR_CARD_STROKE_LIGHT; }

    private View createScreen() {
        FrameLayout root = new FrameLayout(this);
        root.setBackgroundColor(bg());

        ScrollView scrollView = new ScrollView(this);
        scrollView.setFillViewport(true);
        scrollView.setClipToPadding(false);

        LinearLayout content = new LinearLayout(this);
        content.setOrientation(LinearLayout.VERTICAL);
        content.setPadding(dp(20), dp(28), dp(20), dp(28));
        scrollView.addView(content, new ScrollView.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        ));

        content.addView(createTopBar());

        TextView title = textView("Settings", 34, ink(), Typeface.BOLD);
        title.setIncludeFontPadding(false);
        LinearLayout.LayoutParams titleParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        titleParams.setMargins(0, dp(18), 0, dp(18));
        content.addView(title, titleParams);

        content.addView(createDarkModeCard());
        content.addView(createLanguageCard());
        content.addView(createVoiceCard());
        content.addView(createVersionCard());

        checkButton = actionButton(isEnglish ? "Check now" : "Comprobar", COLOR_ACCENT, Color.WHITE);
        checkButton.setOnClickListener(view -> checkForUpdate());
        LinearLayout.LayoutParams checkParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                dp(46)
        );
        checkParams.setMargins(0, dp(16), 0, 0);
        content.addView(checkButton, checkParams);

        downloadButton = actionButton("Download latest APK", COLOR_WARM, Color.WHITE);
        downloadButton.setVisibility(View.GONE);
        downloadButton.setOnClickListener(view -> {
            String url = latestInfo == null ? UpdateManager.APK_URL : latestInfo.apkUrl;
            UpdateManager.openDownload(this, url);
        });
        LinearLayout.LayoutParams downloadParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                dp(46)
        );
        downloadParams.setMargins(0, dp(10), 0, 0);
        content.addView(downloadButton, downloadParams);

        root.addView(scrollView, new FrameLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
        ));

        root.setOnApplyWindowInsetsListener((view, insets) -> {
            content.setPadding(
                    dp(20),
                    dp(28) + insets.getSystemWindowInsetTop(),
                    dp(20),
                    dp(28) + insets.getSystemWindowInsetBottom()
            );
            return insets;
        });
        root.requestApplyInsets();

        return root;
    }

    private View createTopBar() {
        LinearLayout topBar = new LinearLayout(this);
        topBar.setOrientation(LinearLayout.HORIZONTAL);
        topBar.setGravity(Gravity.CENTER_VERTICAL);

        TextView label = textView("APP", 12, COLOR_ACCENT, Typeface.BOLD);
        topBar.addView(label, new LinearLayout.LayoutParams(
                0,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                1f
        ));

        TextView back = textView(isEnglish ? "Extras" : "Extras", 15, COLOR_ACCENT, Typeface.BOLD);
        back.setGravity(Gravity.CENTER);
        back.setPadding(dp(14), 0, dp(14), 0);
        back.setBackground(roundedRect(card(), dp(8), stroke(), dp(1)));
        back.setOnClickListener(view -> finish());
        topBar.addView(back, new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                dp(40)
        ));

        return topBar;
    }

    private View createDarkModeCard() {
        LinearLayout card = createCard();
        card.setOrientation(LinearLayout.HORIZONTAL);
        card.setGravity(Gravity.CENTER_VERTICAL);

        LinearLayout copy = new LinearLayout(this);
        copy.setOrientation(LinearLayout.VERTICAL);

        TextView title = textView(isEnglish ? "Dark Mode" : "Modo oscuro", 20, ink(), Typeface.BOLD);
        title.setIncludeFontPadding(false);
        copy.addView(title);

        TextView subtitle = textView(
                isEnglish ? "Use dark colors for the interface" : "Usar colores oscuros para la interfaz",
                14, muted(), Typeface.NORMAL);
        LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        subtitleParams.setMargins(0, dp(6), 0, 0);
        copy.addView(subtitle, subtitleParams);

        card.addView(copy, new LinearLayout.LayoutParams(
                0,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                1f
        ));

        final Switch darkToggle = new Switch(this);
        darkToggle.setChecked(isDarkMode);
        darkToggle.setOnCheckedChangeListener((buttonView, isChecked) -> {
            UpdateManager.setDarkMode(this, isChecked);
            isDarkMode = isChecked;
            recreate();
        });
        card.addView(darkToggle, new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        ));

        return card;
    }

    private View createLanguageCard() {
        LinearLayout card = createCard();
        card.setOrientation(LinearLayout.HORIZONTAL);
        card.setGravity(Gravity.CENTER_VERTICAL);

        LinearLayout copy = new LinearLayout(this);
        copy.setOrientation(LinearLayout.VERTICAL);

        TextView title = textView("Language", 20, ink(), Typeface.BOLD);
        title.setIncludeFontPadding(false);
        copy.addView(title);

        TextView subtitle = textView("Select the language for daily readings", 14, muted(), Typeface.NORMAL);
        LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        subtitleParams.setMargins(0, dp(6), 0, 0);
        copy.addView(subtitle, subtitleParams);

        card.addView(copy, new LinearLayout.LayoutParams(
                0,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                1f
        ));

        TextView langToggle = actionButton(UpdateManager.isEnglish(this) ? "English" : "Español", COLOR_ACCENT, Color.WHITE);
        langToggle.setOnClickListener(view -> {
            boolean current = UpdateManager.isEnglish(this);
            UpdateManager.setEnglish(this, !current);
            langToggle.setText(!current ? "English" : "Español");
            updateVoiceCard();
        });
        card.addView(langToggle, new LinearLayout.LayoutParams(dp(100), dp(40)));

        return card;
    }

    private View createVoiceCard() {
        LinearLayout card = createCard();
        card.setOrientation(LinearLayout.VERTICAL);

        LinearLayout copy = new LinearLayout(this);
        copy.setOrientation(LinearLayout.VERTICAL);

        TextView title = textView("Voice", 20, ink(), Typeface.BOLD);
        title.setIncludeFontPadding(false);
        copy.addView(title);

        voiceSubtitleText = textView("", 14, muted(), Typeface.NORMAL);
        LinearLayout.LayoutParams subtitleParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        subtitleParams.setMargins(0, dp(6), 0, 0);
        copy.addView(voiceSubtitleText, subtitleParams);

        card.addView(copy, new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        ));

        voiceButton = actionButton("", COLOR_ACCENT, Color.WHITE);
        voiceButton.setOnClickListener(view -> showVoicePicker());
        LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                dp(42)
        );
        buttonParams.setMargins(0, dp(12), 0, 0);
        card.addView(voiceButton, buttonParams);

        updateVoiceCard();
        return card;
    }

    private View createVersionCard() {
        LinearLayout card = createCard();
        card.setOrientation(LinearLayout.VERTICAL);

        TextView title = textView("Version", 20, ink(), Typeface.BOLD);
        title.setIncludeFontPadding(false);
        card.addView(title);

        installedVersionText = textView("", 15, muted(), Typeface.BOLD);
        LinearLayout.LayoutParams installedParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        installedParams.setMargins(0, dp(10), 0, 0);
        card.addView(installedVersionText, installedParams);

        statusText = textView("Ready to check for updates.", 15, muted(), Typeface.NORMAL);
        statusText.setLineSpacing(dp(3), 1.1f);
        LinearLayout.LayoutParams statusParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        statusParams.setMargins(0, dp(8), 0, 0);
        card.addView(statusText, statusParams);

        return card;
    }

    private void checkForUpdate() {
        if (executor == null || executor.isShutdown()) {
            return;
        }

        latestInfo = null;
        downloadButton.setVisibility(View.GONE);
        checkButton.setEnabled(false);
        checkButton.setAlpha(0.62f);
        statusText.setText("Checking for updates...");

        executor.submit(() -> {
            try {
                UpdateManager.UpdateInfo info = UpdateManager.fetchLatestUpdate(this);
                runOnUiThread(() -> showUpdateResult(info));
            } catch (Exception error) {
                runOnUiThread(() -> showUpdateError(error));
            }
        });
    }

    private void showUpdateResult(UpdateManager.UpdateInfo info) {
        latestInfo = info;
        checkButton.setEnabled(true);
        checkButton.setAlpha(1f);

        if (info.updateAvailable) {
            String version = info.latestVersionName.isEmpty()
                    ? String.valueOf(info.latestVersionCode)
                    : info.latestVersionName + " (" + info.latestVersionCode + ")";
            statusText.setText("Update available: " + version);
            downloadButton.setVisibility(View.VISIBLE);
            return;
        }

        statusText.setText("You are on the latest build: "
                + info.currentVersionName + " (" + info.currentVersionCode + ")");
    }

    private void showUpdateError(Exception error) {
        checkButton.setEnabled(true);
        checkButton.setAlpha(1f);
        statusText.setText("Could not check for updates. " + cleanMessage(error));
    }

    private void showVoicePicker() {
        boolean english = UpdateManager.isEnglish(this);
        UpdateManager.VoiceOption[] options = UpdateManager.getTtsVoiceOptions(english);
        String[] labels = new String[options.length];
        for (int index = 0; index < options.length; index++) {
            labels[index] = options[index].label;
        }

        int selectedIndex = UpdateManager.getTtsVoiceIndex(
                english,
                UpdateManager.getTtsVoice(this, english)
        );

        new AlertDialog.Builder(this)
                .setTitle(english ? "English voice" : "Spanish voice")
                .setSingleChoiceItems(labels, selectedIndex, (dialog, which) -> {
                    UpdateManager.setTtsVoice(this, english, options[which].id);
                    updateVoiceCard();
                    dialog.dismiss();
                })
                .setNegativeButton("Cancel", null)
                .show();
    }

    private void updateVoiceCard() {
        if (voiceSubtitleText == null || voiceButton == null) {
            return;
        }

        boolean english = UpdateManager.isEnglish(this);
        String voiceId = UpdateManager.getTtsVoice(this, english);
        voiceSubtitleText.setText(english
                ? "English voices are shown while English is selected"
                : "Las voces en español se muestran mientras el español esté seleccionado");
        voiceButton.setText(UpdateManager.getTtsVoiceLabel(english, voiceId));
    }

    private void updateInstalledVersionText() {
        try {
            installedVersionText.setText(
                    (isEnglish ? "Installed: " : "Instalada: ")
                            + UpdateManager.getInstalledVersionName(this)
                            + " (" + UpdateManager.getInstalledVersionCode(this) + ")");
        } catch (Exception error) {
            installedVersionText.setText(isEnglish ? "Installed version unavailable." : "Versión instalada no disponible.");
        }
    }

    private String cleanMessage(Exception error) {
        String message = error.getMessage();
        if (message == null || message.trim().isEmpty()) {
            return "Unknown error.";
        }
        return message.trim();
    }

    private LinearLayout createCard() {
        LinearLayout card = new LinearLayout(this);
        card.setPadding(dp(18), dp(16), dp(18), dp(16));
        card.setBackground(roundedRect(card(), dp(8), cardStroke(), dp(1)));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            card.setElevation(dp(1));
        }

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
        );
        params.setMargins(0, 0, 0, dp(14));
        card.setLayoutParams(params);
        return card;
    }

    private TextView actionButton(String text, int backgroundColor, int textColor) {
        TextView button = textView(text, 15, textColor, Typeface.BOLD);
        button.setGravity(Gravity.CENTER);
        button.setPadding(dp(14), 0, dp(14), 0);
        button.setBackground(roundedRect(backgroundColor, dp(8), Color.TRANSPARENT, 0));
        return button;
    }

    private TextView textView(String text, int sizeSp, int color, int style) {
        TextView textView = new TextView(this);
        textView.setText(text);
        textView.setTextSize(sizeSp);
        textView.setTextColor(color);
        textView.setTypeface(Typeface.DEFAULT, style);
        return textView;
    }

    private GradientDrawable roundedRect(int color, int radius, int strokeColor, int strokeWidth) {
        GradientDrawable drawable = new GradientDrawable();
        drawable.setShape(GradientDrawable.RECTANGLE);
        drawable.setColor(color);
        drawable.setCornerRadius(radius);
        if (strokeWidth > 0) {
            drawable.setStroke(strokeWidth, strokeColor);
        }
        return drawable;
    }

    private int dp(int value) {
        return Math.round(value * getResources().getDisplayMetrics().density);
    }
}