package de.danoeh.antennapod.ui.screen.feed;

import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.LightingColorFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.databinding.FeedinfoBinding;
import de.danoeh.antennapod.event.MessageEvent;
import de.danoeh.antennapod.storage.database.DBWriter;
import de.danoeh.antennapod.ui.TransitionEffect;
import de.danoeh.antennapod.storage.database.DBReader;
import de.danoeh.antennapod.storage.database.FeedDatabaseWriter;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.ui.common.IntentUtils;
import de.danoeh.antennapod.ui.share.ShareUtils;
import de.danoeh.antennapod.ui.cleaner.HtmlToPlainText;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedFunding;
import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
import de.danoeh.antennapod.ui.screen.feed.preferences.EditUrlSettingsDialog;
import de.danoeh.antennapod.ui.statistics.StatisticsFragment;
import de.danoeh.antennapod.ui.statistics.feed.FeedStatisticsDialogFragment;
import de.danoeh.antennapod.ui.statistics.feed.FeedStatisticsFragment;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.MaybeOnSubscribe;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * Displays information about a feed.
 */
public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenuItemClickListener {

    private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
    private static final String TAG = "FeedInfoActivity";
    private final ActivityResultLauncher<Uri> addLocalFolderLauncher =
            registerForActivityResult(new AddLocalFolder(), this::addLocalFolderResult);

    private Feed feed;
    private Disposable disposable;
    private FeedinfoBinding viewBinding;

    public static FeedInfoFragment newInstance(Feed feed) {
        FeedInfoFragment fragment = new FeedInfoFragment();
        Bundle arguments = new Bundle();
        arguments.putLong(EXTRA_FEED_ID, feed.getId());
        fragment.setArguments(arguments);
        return fragment;
    }

    private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (feed != null && feed.getDownloadUrl() != null) {
                copyToClipboard(requireContext(), feed.getDownloadUrl());
            }
        }
    };

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        viewBinding = FeedinfoBinding.inflate(inflater);
        viewBinding.toolbar.setTitle("");
        viewBinding.toolbar.inflateMenu(R.menu.feedinfo);
        viewBinding.toolbar.setNavigationOnClickListener(v -> getParentFragmentManager().popBackStack());
        viewBinding.toolbar.setOnMenuItemClickListener(this);
        refreshToolbarState();

        ToolbarIconTintManager iconTintManager =
                new ToolbarIconTintManager(viewBinding.toolbar, viewBinding.collapsingToolbar);
        viewBinding.appBar.addOnOffsetChangedListener(iconTintManager);

        viewBinding.header.butShowInfo.setVisibility(View.INVISIBLE);
        viewBinding.header.butShowSettings.setVisibility(View.INVISIBLE);
        viewBinding.header.butFilter.setVisibility(View.INVISIBLE);
        // https://github.com/bumptech/glide/issues/529
        viewBinding.imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
        viewBinding.urlLabel.setOnClickListener(copyUrlToClipboard);

        long feedId = getArguments().getLong(EXTRA_FEED_ID);
        getParentFragmentManager().beginTransaction().replace(R.id.statisticsFragmentContainer,
                        FeedStatisticsFragment.newInstance(feedId, false), "feed_statistics_fragment")
                .commitAllowingStateLoss();
        viewBinding.statisticsFragmentContainer.setOnClickListener(v ->
                FeedStatisticsDialogFragment.newInstance(feedId, feed.getTitle())
                        .show(getChildFragmentManager().beginTransaction(), "FeedStatistics"));

        viewBinding.statisticsButton.setOnClickListener(view -> {
            StatisticsFragment fragment = new StatisticsFragment();
            ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
        });
        viewBinding.header.txtvTitle.setOnLongClickListener(v -> {
            copyToClipboard(requireContext(), viewBinding.header.txtvTitle.getText().toString());
            return true;
        });
        viewBinding.header.txtvAuthor.setOnLongClickListener(v -> {
            copyToClipboard(requireContext(), viewBinding.header.txtvAuthor.getText().toString());
            return true;
        });
        return viewBinding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        long feedId = getArguments().getLong(EXTRA_FEED_ID);
        disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
            Feed feed = DBReader.getFeed(feedId, false, 0, 0);
            if (feed != null) {
                emitter.onSuccess(feed);
            } else {
                emitter.onComplete();
            }
        })
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(result -> {
                    feed = result;
                    showFeed();
                }, error -> Log.d(TAG, Log.getStackTraceString(error)), () -> { });
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (viewBinding == null) {
            return;
        }
        int horizontalSpacing = (int) getResources().getDimension(R.dimen.additional_horizontal_spacing);
        viewBinding.header.getRoot().setPadding(horizontalSpacing, viewBinding.header.getRoot().getPaddingTop(),
                horizontalSpacing, viewBinding.header.getRoot().getPaddingBottom());
        viewBinding.infoContainer.setPadding(horizontalSpacing, viewBinding.infoContainer.getPaddingTop(),
                horizontalSpacing, viewBinding.infoContainer.getPaddingBottom());
    }

    public void copyToClipboard(Context context, String text) {
        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        if (clipboard != null) {
            ClipData clip = ClipData.newPlainText(text, text);
            clipboard.setPrimaryClip(clip);
            if (Build.VERSION.SDK_INT <= 32) {
                EventBus.getDefault().post(new MessageEvent(getString(R.string.copied_to_clipboard)));
            }
        }
    }

    private void showFeed() {
        Log.d(TAG, "Language is " + feed.getLanguage());
        Log.d(TAG, "Author is " + feed.getAuthor());
        Log.d(TAG, "URL is " + feed.getDownloadUrl());
        Glide.with(this)
                .load(feed.getImageUrl())
                .apply(new RequestOptions()
                        .placeholder(R.color.light_gray)
                        .error(R.color.light_gray)
                        .fitCenter()
                        .dontAnimate())
                .into(viewBinding.header.imgvCover);
        Glide.with(this)
                .load(feed.getImageUrl())
                .apply(new RequestOptions()
                        .placeholder(R.color.image_readability_tint)
                        .error(R.color.image_readability_tint)
                        .transform(new FastBlurTransformation())
                        .dontAnimate())
                .into(viewBinding.imgvBackground);

        viewBinding.header.txtvTitle.setText(feed.getTitle());
        viewBinding.header.txtvTitle.setMaxLines(6);

        String description = HtmlToPlainText.getPlainText(feed.getDescription());

        viewBinding.descriptionLabel.setText(description);

        if (!TextUtils.isEmpty(feed.getAuthor())) {
            viewBinding.header.txtvAuthor.setText(feed.getAuthor());
        }

        viewBinding.urlLabel.setText(feed.getDownloadUrl());
        viewBinding.urlLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_paperclip, 0);

        if (feed.getPaymentLinks() == null || feed.getPaymentLinks().size() == 0) {
            viewBinding.supportHeadingLabel.setVisibility(View.GONE);
            viewBinding.supportUrl.setVisibility(View.GONE);
        } else {
            ArrayList<FeedFunding> fundingList = feed.getPaymentLinks();

            // Filter for duplicates, but keep items in the order that they have in the feed.
            Iterator<FeedFunding> i = fundingList.iterator();
            while (i.hasNext()) {
                FeedFunding funding = i.next();
                for (FeedFunding other : fundingList) {
                    if (TextUtils.equals(other.url, funding.url)) {
                        if (other.content != null && funding.content != null
                                && other.content.length() > funding.content.length()) {
                            i.remove();
                            break;
                        }
                    }
                }
            }

            StringBuilder str = new StringBuilder();
            for (FeedFunding funding : fundingList) {
                str.append(funding.content.isEmpty()
                        ? getContext().getResources().getString(R.string.support_podcast)
                        : funding.content).append(" ").append(funding.url);
                str.append("\n");
            }
            str = new StringBuilder(StringUtils.trim(str.toString()));
            viewBinding.supportUrl.setText(str.toString());
        }

        if (feed.getState() == Feed.STATE_NOT_SUBSCRIBED) {
            viewBinding.statisticsHeading.setVisibility(View.GONE);
            viewBinding.statisticsFragmentContainer.setVisibility(View.GONE);
            viewBinding.supportHeadingLabel.setVisibility(View.GONE);
            viewBinding.supportUrl.setVisibility(View.GONE);
            viewBinding.header.butSubscribe.setVisibility(View.VISIBLE);
            viewBinding.header.butSubscribe.setOnClickListener(view -> {
                DBWriter.setFeedState(getContext(), feed, Feed.STATE_SUBSCRIBED);
                MainActivityStarter mainActivityStarter = new MainActivityStarter(getContext());
                mainActivityStarter.withOpenFeed(feed.getId());
                mainActivityStarter.withClearBackStack();
                getActivity().finish();
                startActivity(mainActivityStarter.getIntent());
            });
        } else {
            long feedId = getArguments().getLong(EXTRA_FEED_ID);
            getParentFragmentManager().beginTransaction().replace(R.id.statisticsFragmentContainer,
                            FeedStatisticsFragment.newInstance(feedId, false), "feed_statistics_fragment")
                    .commitAllowingStateLoss();

            viewBinding.statisticsButton.setOnClickListener(view -> {
                StatisticsFragment fragment = new StatisticsFragment();
                ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.SLIDE);
            });
        }

        refreshToolbarState();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (disposable != null) {
            disposable.dispose();
        }
    }

    private void refreshToolbarState() {
        boolean isSubscribed = feed != null && feed.getState() == Feed.STATE_SUBSCRIBED;
        viewBinding.toolbar.getMenu().findItem(R.id.reconnect_local_folder).setVisible(
                isSubscribed && feed.isLocalFeed());
        viewBinding.toolbar.getMenu().findItem(R.id.share_item).setVisible(isSubscribed && !feed.isLocalFeed());
        viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(isSubscribed
                && feed.getLink() != null
                && IntentUtils.isCallable(getContext(), new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
        viewBinding.toolbar.getMenu().findItem(R.id.edit_feed_url_item).setVisible(isSubscribed && !feed.isLocalFeed());
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        if (feed == null) {
            EventBus.getDefault().post(new MessageEvent(getString(R.string.please_wait_for_data)));
            return false;
        }
        if (item.getItemId() == R.id.visit_website_item) {
            IntentUtils.openInBrowser(getContext(), feed.getLink());
        } else if (item.getItemId() == R.id.share_item) {
            ShareUtils.shareFeedLink(getContext(), feed);
        } else if (item.getItemId() == R.id.reconnect_local_folder) {
            MaterialAlertDialogBuilder alert = new MaterialAlertDialogBuilder(getContext());
            alert.setMessage(R.string.reconnect_local_folder_warning);
            alert.setPositiveButton(android.R.string.ok, (dialog, which) -> {
                try {
                    addLocalFolderLauncher.launch(null);
                } catch (ActivityNotFoundException e) {
                    Log.e(TAG, "No activity found. Should never happen...");
                }
            });
            alert.setNegativeButton(android.R.string.cancel, null);
            alert.show();
        } else if (item.getItemId() == R.id.edit_feed_url_item) {
            new EditUrlSettingsDialog(getActivity(), feed) {
                @Override
                protected void setUrl(String url) {
                    feed.setDownloadUrl(url);
                    viewBinding.urlLabel.setText(feed.getDownloadUrl());
                    viewBinding.urlLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(
                            0, 0, R.drawable.ic_paperclip, 0);
                }
            }.show();
        } else {
            return false;
        }
        return true;
    }

    private void addLocalFolderResult(final Uri uri) {
        if (uri == null) {
            return;
        }
        reconnectLocalFolder(uri);
    }

    private void reconnectLocalFolder(Uri uri) {
        if (feed == null) {
            return;
        }

        Completable.fromAction(() -> {
            getActivity().getContentResolver()
                    .takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION
                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            DocumentFile documentFile = DocumentFile.fromTreeUri(getContext(), uri);
            if (documentFile == null) {
                throw new IllegalArgumentException("Unable to retrieve document tree");
            }
            feed.setDownloadUrl(Feed.PREFIX_LOCAL_FOLDER + uri.toString());
            FeedDatabaseWriter.updateFeed(getContext(), feed, false);
        })
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        () -> EventBus.getDefault().post(new MessageEvent(getString(android.R.string.ok))),
                        error -> EventBus.getDefault().post(new MessageEvent(error.getLocalizedMessage())));
    }

    private static class AddLocalFolder extends ActivityResultContracts.OpenDocumentTree {
        @NonNull
        @Override
        public Intent createIntent(@NonNull final Context context, @Nullable final Uri input) {
            return super.createIntent(context, input)
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                            | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
        }
    }
}
