package de.danoeh.antennapod.activity;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission;
import androidx.annotation.Nullable;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import androidx.core.app.ActivityCompat;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;

import de.danoeh.antennapod.storage.database.FeedDatabaseWriter;
import de.danoeh.antennapod.databinding.OpmlSelectionBinding;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.storage.importexport.OpmlElement;
import de.danoeh.antennapod.storage.importexport.OpmlReader;
import de.danoeh.antennapod.ui.common.ToolbarActivity;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.schedulers.Schedulers;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

/**
 * Activity for Opml Import.
 * */
public class OpmlImportActivity extends ToolbarActivity {
    private static final String TAG = "OpmlImportBaseActivity";
    @Nullable private Uri uri;
    private OpmlSelectionBinding viewBinding;
    private ArrayAdapter<String> listAdapter;
    private MenuItem selectAll;
    private MenuItem deselectAll;
    private ArrayList<OpmlElement> readElements;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        viewBinding = OpmlSelectionBinding.inflate(getLayoutInflater());
        setContentView(viewBinding.getRoot());

        viewBinding.feedlist.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        viewBinding.feedlist.setOnItemClickListener((parent, view, position, id) -> {
            SparseBooleanArray checked = viewBinding.feedlist.getCheckedItemPositions();
            int checkedCount = 0;
            for (int i = 0; i < checked.size(); i++) {
                if (checked.valueAt(i)) {
                    checkedCount++;
                }
            }
            if (checkedCount == listAdapter.getCount()) {
                selectAll.setVisible(false);
                deselectAll.setVisible(true);
            } else {
                deselectAll.setVisible(false);
                selectAll.setVisible(true);
            }
        });
        viewBinding.butCancel.setOnClickListener(v -> {
            setResult(RESULT_CANCELED);
            finish();
        });
        viewBinding.butConfirm.setOnClickListener(v -> {
            viewBinding.progressBar.setVisibility(View.VISIBLE);
            Completable.fromAction(() -> {
                SparseBooleanArray checked = viewBinding.feedlist.getCheckedItemPositions();
                for (int i = 0; i < checked.size(); i++) {
                    if (!checked.valueAt(i)) {
                        continue;
                    }
                    OpmlElement element = readElements.get(checked.keyAt(i));
                    Feed feed = new Feed(element.getXmlUrl(), null,
                            element.getText() != null ? element.getText() : "Unknown podcast");
                    feed.setItems(Collections.emptyList());
                    FeedDatabaseWriter.updateFeed(this, feed, false);
                }
                FeedUpdateManager.getInstance().runOnce(this);
            })
                    .subscribeOn(Schedulers.computation())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                            () -> {
                                viewBinding.progressBar.setVisibility(View.GONE);
                                Intent intent = new Intent(OpmlImportActivity.this, MainActivity.class);
                                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                                startActivity(intent);
                                finish();
                            }, e -> {
                                e.printStackTrace();
                                viewBinding.progressBar.setVisibility(View.GONE);
                                Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
                            });
        });

        Uri uri = getIntent().getData();
        if (uri != null && uri.toString().startsWith("/")) {
            uri = Uri.parse("file://" + uri.toString());
        } else {
            String extraText = getIntent().getStringExtra(Intent.EXTRA_TEXT);
            if (extraText != null) {
                uri = Uri.parse(extraText);
            }
        }
        importUri(uri);
    }

    void importUri(@Nullable Uri uri) {
        if (uri == null) {
            new MaterialAlertDialogBuilder(this)
                    .setMessage(R.string.opml_import_error_no_file)
                    .setPositiveButton(android.R.string.ok, null)
                    .show();
            return;
        }
        this.uri = uri;
        startImport();
    }

    private List<String> getTitleList() {
        List<String> result = new ArrayList<>();
        if (readElements != null) {
            for (OpmlElement element : readElements) {
                result.add(element.getText());
            }
        }
        return result;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.opml_selection_options, menu);
        selectAll = menu.findItem(R.id.select_all_item);
        deselectAll = menu.findItem(R.id.deselect_all_item);
        deselectAll.setVisible(false);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        final int itemId = item.getItemId();
        if (itemId == R.id.select_all_item) {
            selectAll.setVisible(false);
            selectAllItems(true);
            deselectAll.setVisible(true);
            return true;
        } else if (itemId == R.id.deselect_all_item) {
            deselectAll.setVisible(false);
            selectAllItems(false);
            selectAll.setVisible(true);
            return true;
        } else if (itemId == android.R.id.home) {
            finish();
        }
        return false;
    }

    private void selectAllItems(boolean b) {
        for (int i = 0; i < viewBinding.feedlist.getCount(); i++) {
            viewBinding.feedlist.setItemChecked(i, b);
        }
    }

    private void requestPermission() {
        requestPermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE);
    }

    private final ActivityResultLauncher<String> requestPermissionLauncher =
            registerForActivityResult(new RequestPermission(), isGranted -> {
                if (isGranted) {
                    startImport();
                } else {
                    new MaterialAlertDialogBuilder(this)
                            .setMessage(R.string.opml_import_ask_read_permission)
                            .setPositiveButton(android.R.string.ok, (dialog, which) ->
                                    requestPermission())
                            .setNegativeButton(R.string.cancel_label, (dialog, which) ->
                                    finish())
                            .show();
                }
            });

    /** Starts the import process. */
    private void startImport() {
        viewBinding.progressBar.setVisibility(View.VISIBLE);

        Observable.fromCallable(() -> {
            InputStream opmlFileStream = getContentResolver().openInputStream(uri);
            BOMInputStream bomInputStream = new BOMInputStream(opmlFileStream);
            ByteOrderMark bom = bomInputStream.getBOM();
            String charsetName = (bom == null) ? "UTF-8" : bom.getCharsetName();
            Reader reader = new InputStreamReader(bomInputStream, charsetName);
            OpmlReader opmlReader = new OpmlReader();
            ArrayList<OpmlElement> result = opmlReader.readDocument(reader);
            reader.close();
            return result;
        })
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        result -> {
                            viewBinding.progressBar.setVisibility(View.GONE);
                            Log.d(TAG, "Parsing was successful");
                            readElements = result;
                            listAdapter = new ArrayAdapter<>(OpmlImportActivity.this,
                                    android.R.layout.simple_list_item_multiple_choice,
                                    getTitleList());
                            viewBinding.feedlist.setAdapter(listAdapter);
                        }, e -> {
                            Log.d(TAG, Log.getStackTraceString(e));
                            String message = e.getMessage() == null ? "" : e.getMessage();
                            if (message.toLowerCase(Locale.ROOT).contains("permission")
                                    && Build.VERSION.SDK_INT >= 23) {
                                int permission = ActivityCompat.checkSelfPermission(this,
                                        android.Manifest.permission.READ_EXTERNAL_STORAGE);
                                if (permission != PackageManager.PERMISSION_GRANTED) {
                                    requestPermission();
                                    return;
                                }
                            }
                            viewBinding.progressBar.setVisibility(View.GONE);
                            MaterialAlertDialogBuilder alert = new MaterialAlertDialogBuilder(this);
                            alert.setTitle(R.string.error_label);
                            String userReadable = getString(R.string.opml_reader_error);
                            String details = e.getMessage();
                            String total = userReadable + "\n\n" + details;
                            SpannableString errorMessage = new SpannableString(total);
                            errorMessage.setSpan(new ForegroundColorSpan(0x88888888),
                                    userReadable.length(), total.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                            alert.setMessage(errorMessage);
                            alert.setPositiveButton(android.R.string.ok, (dialog, which) -> finish());
                            alert.show();
                        });
    }
}
