/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2012-2014 lacolaco.net
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package net.lacolaco.smileessence.view.dialog;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Html;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.*;

import com.android.volley.toolbox.NetworkImageView;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshListView;

import net.lacolaco.smileessence.R;
import net.lacolaco.smileessence.activity.MainActivity;
import net.lacolaco.smileessence.command.Command;
import net.lacolaco.smileessence.command.CommandOpenURL;
import net.lacolaco.smileessence.data.ImageCache;
import net.lacolaco.smileessence.entity.Account;
import net.lacolaco.smileessence.logging.Logger;
import net.lacolaco.smileessence.twitter.Consumer;
import net.lacolaco.smileessence.twitter.TwitterApi;
import net.lacolaco.smileessence.twitter.task.FollowTask;
import net.lacolaco.smileessence.twitter.task.ShowFriendshipTask;
import net.lacolaco.smileessence.twitter.task.UnfollowTask;
import net.lacolaco.smileessence.twitter.task.UserTimelineTask;
import net.lacolaco.smileessence.twitter.util.TwitterUtils;
import net.lacolaco.smileessence.util.Themes;
import net.lacolaco.smileessence.util.UIHandler;
import net.lacolaco.smileessence.view.adapter.CustomListAdapter;
import net.lacolaco.smileessence.view.adapter.StatusListAdapter;
import net.lacolaco.smileessence.viewmodel.StatusViewModel;

import twitter4j.Paging;
import twitter4j.Relationship;
import twitter4j.Twitter;
import twitter4j.User;

public class UserDetailDialogFragment extends DialogFragment implements View.OnClickListener,
        PullToRefreshBase.OnRefreshListener2<ListView> {

    // ------------------------------ FIELDS ------------------------------

    public static final String USER_MENU_DIALOG = "userMenuDialog";
    private static final String KEY_USER_ID = "userID";
    private static final int ADAPTER_INDEX = 100;
    private TextView textViewScreenName;
    private TextView textViewName;
    private TextView textViewURL;
    private TextView textViewLocate;
    private TextView textViewFollowed;
    private TextView textViewProtected;
    private TextView textViewDescription;
    private TextView textViewTweetCount;
    private TextView textViewFriendCount;
    private TextView textViewFollowerCount;
    private TextView textViewFavoriteCount;
    private NetworkImageView imageViewIcon;
    private NetworkImageView imageViewHeader;
    private Button buttonFollow;
    private PullToRefreshListView listViewTimeline;
    private TabHost tabHost;

    // --------------------- GETTER / SETTER METHODS ---------------------

    public long getUserID() {
        return getArguments().getLong(KEY_USER_ID);
    }

    public void setUserID(long userID) {
        Bundle args = new Bundle();
        args.putLong(KEY_USER_ID, userID);
        setArguments(args);
    }

    // ------------------------ INTERFACE METHODS ------------------------


    // --------------------- Interface OnClickListener ---------------------

    @Override
    public void onClick(final View v) {
        final MainActivity activity = (MainActivity) getActivity();
        final Account account = activity.getAccount();
        final Consumer consumer = activity.getConsumer();
        final Twitter twitter = TwitterApi.getTwitter(consumer, account);

        TwitterUtils.tryGetUser(twitter, account, getUserID(), new TwitterUtils.UserCallback() {
            @Override
            public void success(final User user) {
                switch (v.getId()) {
                    case R.id.imageview_user_detail_menu: {
                        openUserMenu(activity, user);
                        break;
                    }
                    case R.id.imageview_user_detail_icon: {
                        openUrl(user.getBiggerProfileImageURLHttps());
                        break;
                    }
                    case R.id.textview_user_detail_screenname: {
                        openUrl(TwitterUtils.getUserHomeURL(user.getScreenName()));
                        break;
                    }
                    case R.id.textview_user_detail_tweet_count: {
                        openUrl(TwitterUtils.getUserHomeURL(user.getScreenName()));
                        break;
                    }
                    case R.id.textview_user_detail_friend_count: {
                        openUrl(String.format("%s/following", TwitterUtils.getUserHomeURL(user.getScreenName())));
                        break;
                    }
                    case R.id.textview_user_detail_follower_count: {
                        openUrl(String.format("%s/followers", TwitterUtils.getUserHomeURL(user.getScreenName())));
                        break;
                    }
                    case R.id.textview_user_detail_favorite_count: {
                        openUrl(String.format("%s/favorites", TwitterUtils.getUserHomeURL(user.getScreenName())));
                        break;
                    }
                    case R.id.button_user_detail_follow: {
                        ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands), new Runnable() {
                            @Override
                            public void run() {
                                toggleFollowing(user, twitter, activity);
                            }
                        });
                        break;
                    }
                }
            }

            @Override
            public void error() {
                dismiss();
            }
        });
    }

    // --------------------- Interface OnRefreshListener2 ---------------------

    @Override
    public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) {
        final MainActivity activity = (MainActivity) getActivity();
        final Account account = activity.getAccount();
        final Consumer consumer = activity.getConsumer();
        Twitter twitter = TwitterApi.getTwitter(consumer, account);

        final StatusListAdapter adapter = getListAdapter(activity);
        Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity));
        if (adapter.getCount() > 0) {
            paging.setSinceId(adapter.getTopID());
        }
        new UserTimelineTask(twitter, getUserID(), paging) {
            @Override
            protected void onPostExecute(twitter4j.Status[] statuses) {
                super.onPostExecute(statuses);
                for (int i = statuses.length - 1; i >= 0; i--) {
                    twitter4j.Status status = statuses[i];
                    adapter.addToTop(new StatusViewModel(status, account));
                }
                updateListView(refreshView.getRefreshableView(), adapter, true);
                refreshView.onRefreshComplete();
            }
        }.execute();
    }

    @Override
    public void onPullUpToRefresh(final PullToRefreshBase<ListView> refreshView) {
        final MainActivity activity = (MainActivity) getActivity();
        final Account account = activity.getAccount();
        final Consumer consumer = activity.getConsumer();
        Twitter twitter = TwitterApi.getTwitter(consumer, account);

        final StatusListAdapter adapter = getListAdapter(activity);
        Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity));
        if (adapter.getCount() > 0) {
            paging.setMaxId(adapter.getLastID() - 1);
        }
        new UserTimelineTask(twitter, getUserID(), paging) {
            @Override
            protected void onPostExecute(twitter4j.Status[] statuses) {
                super.onPostExecute(statuses);
                for (twitter4j.Status status : statuses) {
                    adapter.addToBottom(new StatusViewModel(status, account));
                }
                updateListView(refreshView.getRefreshableView(), adapter, false);
                refreshView.onRefreshComplete();
            }
        }.execute();
    }

    // ------------------------ OVERRIDE METHODS ------------------------

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        MainActivity activity = (MainActivity) getActivity();
        View v = activity.getLayoutInflater().inflate(R.layout.dialog_user_detail, null);
        View menu = v.findViewById(R.id.imageview_user_detail_menu);
        menu.setOnClickListener(this);
        textViewScreenName = (TextView) v.findViewById(R.id.textview_user_detail_screenname);
        textViewScreenName.setOnClickListener(this);
        textViewName = (TextView) v.findViewById(R.id.textview_user_detail_name);
        textViewURL = (TextView) v.findViewById(R.id.textview_user_detail_url);
        textViewLocate = (TextView) v.findViewById(R.id.textview_user_detail_locate);
        textViewFollowed = (TextView) v.findViewById(R.id.textview_user_detail_followed);
        textViewProtected = (TextView) v.findViewById(R.id.texttview_user_detail_protected);
        textViewDescription = (TextView) v.findViewById(R.id.textview_user_detail_description);
        textViewTweetCount = (TextView) v.findViewById(R.id.textview_user_detail_tweet_count);
        textViewTweetCount.setOnClickListener(this);
        textViewFriendCount = (TextView) v.findViewById(R.id.textview_user_detail_friend_count);
        textViewFriendCount.setOnClickListener(this);
        textViewFollowerCount = (TextView) v.findViewById(R.id.textview_user_detail_follower_count);
        textViewFollowerCount.setOnClickListener(this);
        textViewFavoriteCount = (TextView) v.findViewById(R.id.textview_user_detail_favorite_count);
        textViewFavoriteCount.setOnClickListener(this);
        imageViewIcon = (NetworkImageView) v.findViewById(R.id.imageview_user_detail_icon);
        imageViewIcon.setOnClickListener(this);
        imageViewHeader = (NetworkImageView) v.findViewById(R.id.imageview_user_detail_header);
        buttonFollow = (Button) v.findViewById(R.id.button_user_detail_follow);
        buttonFollow.setOnClickListener(this);
        listViewTimeline = (PullToRefreshListView) v.findViewById(R.id.listview_user_detail_timeline);

        tabHost = (TabHost) v.findViewById(android.R.id.tabhost);
        tabHost.setup();
        TabHost.TabSpec tab1 = tabHost.newTabSpec("tab1").setContent(R.id.tab1).setIndicator(getString(R.string.user_detail_tab_info));
        tabHost.addTab(tab1);
        TabHost.TabSpec tab2 = tabHost.newTabSpec("tab2").setContent(R.id.tab2).setIndicator(getString(R.string.user_detail_tab_timeline));
        tabHost.addTab(tab2);
        tabHost.setCurrentTab(0);

        final Account account = activity.getAccount();
        final Consumer consumer = activity.getConsumer();
        final Twitter twitter = TwitterApi.getTwitter(consumer, account);

        TwitterUtils.tryGetUser(twitter, account, getUserID(), new TwitterUtils.UserCallback() {
            @Override
            public void success(User user) {
                try {
                    initUserData(user, twitter, account);
                } catch (Exception e) {
                    Logger.error(e);
                    error();
                }
            }

            @Override
            public void error() {
                dismiss();
            }
        });
        return new AlertDialog.Builder(activity)
                .setView(v)
                .setCancelable(true)
                .create();
    }

    private void executeUserTimelineTask(final User user, Twitter twitter ,final Account account, final StatusListAdapter adapter) {
        tabHost.getTabWidget().getChildTabViewAt(1).setVisibility(View.GONE);
        new UserTimelineTask(twitter, user.getId()) {
            @Override
            protected void onPostExecute(twitter4j.Status[] statuses) {
                super.onPostExecute(statuses);
                for (twitter4j.Status status : statuses) {
                    adapter.addToBottom(new StatusViewModel(status, account));
                }
                adapter.updateForce();
                tabHost.getTabWidget().getChildTabViewAt(1).setVisibility(View.VISIBLE);
            }
        }.execute();
    }

    private String getHtmlDescription(String description) {
        if (TextUtils.isEmpty(description)) {
            return "";
        }
        String html = description;
        html = html.replaceAll("https?://[\\w/:%#\\$&\\?\\(\\)~\\.=\\+\\-]+", "<a href=\"$0\">$0</a>");
        html = html.replaceAll("@([a-zA-Z0-9_]+)", "<a href=\"" + TwitterUtils.getUserHomeURL("$1") + "\">$0</a>");
        html = html.replaceAll("\r\n", "<br />");
        return html;
    }

    private StatusListAdapter getListAdapter(MainActivity activity) {
        return (StatusListAdapter) activity.getListAdapter(ADAPTER_INDEX);
    }

    private void initUserData(User user, Twitter twitter, final Account account) {
        textViewName.setText(user.getName());
        textViewScreenName.setText(user.getScreenName());
        if (TextUtils.isEmpty(user.getLocation())) {
            textViewLocate.setVisibility(View.GONE);
        } else {
            textViewLocate.setText(user.getLocation());
        }
        if (TextUtils.isEmpty(user.getURL())) {
            textViewURL.setVisibility(View.GONE);
        } else {
            textViewURL.setText(user.getURL());
        }
        textViewTweetCount.setText(String.valueOf(user.getStatusesCount()));
        textViewFriendCount.setText(String.valueOf(user.getFriendsCount()));
        textViewFollowerCount.setText(String.valueOf(user.getFollowersCount()));
        textViewFavoriteCount.setText(String.valueOf(user.getFavouritesCount()));
        textViewProtected.setVisibility(user.isProtected() ? View.VISIBLE : View.GONE);
        String htmlDescription = getHtmlDescription(user.getDescription());
        textViewDescription.setText(Html.fromHtml(htmlDescription));
        textViewDescription.setMovementMethod(LinkMovementMethod.getInstance());
        ImageCache.getInstance().setImageToView(user.getBiggerProfileImageURL(), imageViewIcon);
        ImageCache.getInstance().setImageToView(user.getProfileBannerURL(), imageViewHeader);
        MainActivity activity = (MainActivity) getActivity();
        final StatusListAdapter adapter = new StatusListAdapter(activity);
        listViewTimeline.setAdapter(adapter);
        listViewTimeline.setOnRefreshListener(this);
        activity.setListAdapter(ADAPTER_INDEX, adapter);
        executeUserTimelineTask(user, twitter, account, adapter);
        updateRelationship(activity, user.getId());
    }

    private void lockFollowButton(Activity activity) {
        buttonFollow.setText(R.string.user_detail_loading);
        buttonFollow.setBackground(activity.getResources().getDrawable(R.drawable.button_round_gray));
        buttonFollow.setEnabled(false);
    }

    private void openUrl(String url) {
        new CommandOpenURL(getActivity(), url).execute();
    }

    private void openUserMenu(final MainActivity activity, final User user) {
        UserMenuDialogFragment menuFragment = new UserMenuDialogFragment() {
            @Override
            protected void executeCommand(Command command) {
                super.executeCommand(command);
                new UIHandler() {
                    @Override
                    public void run() {
                        if (UserDetailDialogFragment.this.isDetached()) {
                            return;
                        }
                        updateRelationship(activity, user.getId());
                    }
                }.postDelayed(1000);
            }
        };
        menuFragment.setUserID(user.getId());
        DialogHelper.showDialog(activity, menuFragment, USER_MENU_DIALOG);
    }

    private void setFollowButtonState(boolean isFollowing, Drawable unfollowColor, Drawable followColor) {
        buttonFollow.setText(isFollowing ? R.string.user_detail_unfollow : R.string.user_detail_follow);
        buttonFollow.setBackground(isFollowing ? unfollowColor : followColor);
        buttonFollow.setTag(isFollowing);
        buttonFollow.setEnabled(true);
    }

    private void toggleFollowing(final User user, final Twitter twitter, final Activity activity) {
        lockFollowButton(activity);
        Boolean isFollowing = buttonFollow.getTag() != null ? (Boolean) buttonFollow.getTag() : false;
        if (isFollowing) {
            new UnfollowTask(twitter, user.getId(), activity) {
                @Override
                public void onPostExecute(User result) {
                    super.onPostExecute(result);
                    updateRelationship(activity, user.getId());
                    buttonFollow.setEnabled(true);
                }
            }.execute();
        } else {
            new FollowTask(twitter, user.getId(), activity) {
                @Override
                public void onPostExecute(User result) {
                    super.onPostExecute(result);
                    updateRelationship(activity, user.getId());
                    buttonFollow.setEnabled(true);
                }
            }.execute();
        }
    }

    protected void updateListView(AbsListView absListView, CustomListAdapter<?> adapter, boolean addedToTop) {
        int before = adapter.getCount();
        adapter.notifyDataSetChanged(); // synchronized call (not adapter#updateForce())
        int after = adapter.getCount();
        int increments = after - before;
        if (increments > 0) {
            adapter.setNotifiable(false);
            if (addedToTop) {
                absListView.setSelection(increments + 1);
                absListView.smoothScrollToPositionFromTop(increments, 0);
                absListView.setSelection(increments);
            } else {
                absListView.smoothScrollToPositionFromTop(before, 0);
            }

            if (increments == 1) {
                adapter.setNotifiable(true);
            }
        } else {
            adapter.setNotifiable(true);
        }
    }

    private void updateRelationship(Activity activity, final long userId) {
        MainActivity mainActivity = (MainActivity) activity;
        final Account account = mainActivity.getAccount();
        final Consumer consumer = mainActivity.getConsumer();
        Twitter twitter = TwitterApi.getTwitter(consumer, account);

        if (userId == account.userID) {
            textViewFollowed.setText(R.string.user_detail_followed_is_me);
            buttonFollow.setVisibility(View.GONE);
        } else {
            int theme = mainActivity.getThemeIndex();
            lockFollowButton(activity);
            textViewFollowed.setText(R.string.user_detail_loading);
            final Drawable red = Themes.getStyledDrawable(activity, theme, R.attr.button_round_red);
            final Drawable blue = Themes.getStyledDrawable(activity, theme, R.attr.button_round_blue);
            new ShowFriendshipTask(twitter, userId) {
                @Override
                protected void onPostExecute(Relationship relationship) {
                    if (relationship != null) {
                        boolean isFollowing = relationship.isSourceFollowingTarget();
                        boolean isFollowed = relationship.isSourceFollowedByTarget();
                        setFollowButtonState(isFollowing, red, blue);
                        textViewFollowed.setText(isFollowed ? R.string.user_detail_followed : R.string.user_detail_not_followed);
                    }
                }
            }.execute();
        }
    }
}