package io.mrarm.irc;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import io.mrarm.chatlib.ChatApi;
import io.mrarm.irc.config.ServerConfigData;
import io.mrarm.irc.config.ServerConfigManager;
import io.mrarm.irc.util.AdvancedDividerItemDecoration;

public class IRCLinkActivity extends ThemedActivity {

    private static final int REQUEST_ADD_SERVER = 100;

    private String mHostName;
    private String mChannelName;
    private ServerConnectionInfo mSelectedConnection;
    private OpenTaskChannelListListener mOpenTask;

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

        if (getIntent() == null || getIntent().getAction() == null ||
                !getIntent().getAction().equals(Intent.ACTION_VIEW) ||
                getIntent().getData() == null) {
            finish();
            return;
        }

        RecyclerView recyclerView = new RecyclerView(this);
        setContentView(recyclerView);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        String str = getIntent().getData().toString();
        int iof = str.indexOf(":/");
        if (iof == -1) {
            finish();
            return;
        }
        iof += 2;
        if (str.length() > iof && str.charAt(iof) == '/')
            iof++;
        str = str.substring(iof);
        iof = str.indexOf('/');
        if (iof == -1) {
            finish();
            return;
        }
        mHostName = str.substring(0, iof);
        mChannelName = prefixChannelIfNeeded(str.substring(iof + 1));

        LinkServerListAdapter adapter = new LinkServerListAdapter(
                this, mHostName, mChannelName);
        recyclerView.setAdapter(adapter);
        recyclerView.addItemDecoration(adapter.createItemDecoration(this));
    }

    private static String prefixChannelIfNeeded(String name) {
        if (name == null || name.length() == 0)
            return "";
        char c = name.charAt(0);
        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
            return "#" + name;
        return name;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ADD_SERVER && data != null && data.getAction() != null &&
                data.getAction().equals(EditServerActivity.RESULT_ACTION)) {
            ServerConnectionManager mgr = ServerConnectionManager.getInstance(this);

            String uuid = data.getStringExtra(EditServerActivity.ARG_SERVER_UUID);
            openServer(ServerConfigManager.getInstance(this).findServer(
                    UUID.fromString(uuid)));
            return;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mOpenTask != null) {
            mSelectedConnection.removeOnChannelListChangeListener(mOpenTask);
        }
    }

    public void openServer(ServerConfigData server) {
        if (mSelectedConnection != null)
            throw new RuntimeException();

        ArrayList<String> channels = new ArrayList<>();
        channels.add(mChannelName);

        ServerConnectionManager mgr = ServerConnectionManager.getInstance(this);
        if (!mgr.hasConnection(server.uuid))
            mgr.tryCreateConnection(server, this);
        ServerConnectionInfo connection = mgr.getConnection(server.uuid);
        if (connection == null)
            return;
        mSelectedConnection = connection;
        ChatApi api = connection.getApiInstance();
        if (api == null)
            return;
        if (connection.hasChannel(mChannelName)) {
            startActivity(MainActivity.getLaunchIntent(this, connection, mChannelName));
            finish();
            return;
        }
        setContentView(R.layout.dialog_please_wait);
        api.joinChannels(channels, (Void vv) -> {
            if (connection.hasChannel(mChannelName)) {
                startActivity(MainActivity.getLaunchIntent(this, connection, mChannelName));
                finish();
                return;
            }
            mOpenTask = new OpenTaskChannelListListener(mChannelName);
            connection.addOnChannelListChangeListener(mOpenTask);
        }, (Exception e) -> finish());
    }

    private class OpenTaskChannelListListener
            implements ServerConnectionInfo.ChannelListChangeListener {

        private String mChannel;

        public OpenTaskChannelListListener(String channel) {
            mChannel = channel;
        }

        @Override
        public void onChannelListChanged(ServerConnectionInfo connection, List<String> newChannels) {
            if (newChannels.contains(mChannel)) {
                startActivity(MainActivity.getLaunchIntent(IRCLinkActivity.this,
                        connection, mChannel));
                connection.removeOnChannelListChangeListener(this);
                mOpenTask = null;
                finish();
            }
        }

    }

    private static class LinkServerListAdapter extends RecyclerView.Adapter {

        private static final int TYPE_TEXT = 0;
        private static final int TYPE_HEADER = 1;
        private static final int TYPE_SERVER_ITEM = 2;
        private static final int TYPE_ACTION_ITEM = 3;

        private IRCLinkActivity mContext;
        private String mHostName;
        private String mChannelName;
        private List<ServerConfigData> mActiveServers;
        private List<ServerConfigData> mInactiveServers;

        public LinkServerListAdapter(IRCLinkActivity context, String hostName, String channelName) {
            mContext = context;
            mHostName = hostName;
            mChannelName = channelName;
            reloadServerList(true);
        }

        /**
         * Returns the main domain for the specified hostname.
         * Example: test.freenode.net => freenode.net
         */
        private String getHostnameDomain(String hname) {
            if (hname == null || hname.isEmpty())
                return hname;
            int iof = hname.lastIndexOf('.');
            if (iof <= 0)
                return hname;
            iof = hname.lastIndexOf('.', iof - 1);
            if (iof <= 0)
                return hname;
            return hname.substring(iof + 1);
        }

        private void reloadServerList(boolean filter) {
            mActiveServers = new ArrayList<>();
            mInactiveServers = new ArrayList<>();
            ServerConnectionManager connectionManager =
                    ServerConnectionManager.getInstance(mContext);
            for (ServerConfigData server : ServerConfigManager.getInstance(mContext).getServers()) {
                if (filter) {
                    if (!getHostnameDomain(server.address).equals(getHostnameDomain(mHostName)))
                        continue;
                }
                if (connectionManager .hasConnection(server.uuid))
                    mActiveServers.add(server);
                else
                    mInactiveServers.add(server);
            }
            notifyDataSetChanged();
        }

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            if (viewType == TYPE_TEXT) {
                View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.irc_link_header_text_item, parent, false);
                return new TextHolder(view);
            } else if (viewType == TYPE_HEADER) {
                View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.settings_list_header, parent, false);
                return new TextHolder(view);
            } else if (viewType == TYPE_SERVER_ITEM) {
                View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.simple_list_item, parent, false);
                return new ServerHolder(view);
            } else if (viewType == TYPE_ACTION_ITEM) {
                View view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.simple_list_item_with_icon, parent, false);
                return new ActionHolder(view);
            }
            throw new IllegalArgumentException();
        }

        private boolean hasActiveHeader() {
            return mActiveServers.size() > 0;
        }

        private int getActiveHeaderIndex() {
            return 1;
        }

        private int getActiveListStart() {
            return hasActiveHeader() ? getActiveHeaderIndex() + 1 : getActiveHeaderIndex();
        }

        private boolean hasInactiveHeader() {
            return hasActiveHeader() && mInactiveServers.size() > 0;
        }

        private int getInactiveHeaderIndex() {
            return 1 + (hasActiveHeader() ? 1 : 0) + mActiveServers.size();
        }

        private int getInactiveListStart() {
            return hasInactiveHeader() ? getInactiveHeaderIndex() + 1 : getInactiveHeaderIndex();
        }

        private int getExtraActionsHeaderIndex() {
            return getInactiveListStart() + mInactiveServers.size();
        }

        private int getExtraActionsStart() {
            return getExtraActionsHeaderIndex() + 1;
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            if (position == 0)
                ((TextHolder) holder).bind(holder.itemView.getResources()
                        .getString(R.string.irc_link_pick_header, mHostName, mChannelName));
            else if (hasActiveHeader() && position == getActiveHeaderIndex())
                ((TextHolder) holder).bind(R.string.server_list_header_active);
            else if (position >= getActiveListStart() &&
                    position < getActiveListStart() + mActiveServers.size())
                ((ServerHolder) holder).bind(mActiveServers.get(position - getActiveListStart()));
            else if (hasInactiveHeader() && position == getInactiveHeaderIndex())
                ((TextHolder) holder).bind(R.string.server_list_header_inactive);
            else if (position >= getInactiveListStart() &&
                    position < getInactiveListStart() + mInactiveServers.size())
                ((ServerHolder) holder).bind(mInactiveServers.get(position - getInactiveListStart()));
            else if (position == getExtraActionsHeaderIndex())
                ((TextHolder) holder).bind(R.string.notification_header_options);
            else if (position == getExtraActionsStart())
                ((ActionHolder) holder).bind(ActionHolder.ACTION_ADD);
            else if (position == getExtraActionsStart() + 1)
                ((ActionHolder) holder).bind(ActionHolder.ACTION_SHOW_ALL);
        }

        @Override
        public int getItemCount() {
            return 1 + (hasActiveHeader() ? 1 : 0) + mActiveServers.size() +
                    (hasInactiveHeader() ? 1 : 0) + mInactiveServers.size() + 3;
        }

        @Override
        public int getItemViewType(int position) {
            if (position == 0)
                return TYPE_TEXT;
            if ((hasActiveHeader() && position == getActiveHeaderIndex()) ||
                    (hasInactiveHeader() && position == getInactiveHeaderIndex()) ||
                    position == getExtraActionsHeaderIndex())
                return TYPE_HEADER;
            if (position >= getExtraActionsStart())
                return TYPE_ACTION_ITEM;
            return TYPE_SERVER_ITEM;
        }

        public ItemDecoration createItemDecoration(Context context) {
            return new ItemDecoration(context);
        }

        public static class ItemDecoration extends AdvancedDividerItemDecoration {

            public ItemDecoration(Context context) {
                super(context);
            }

            @Override
            public boolean hasDivider(RecyclerView parent, View view) {
                RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
                int viewType = holder.getItemViewType();
                return viewType != TYPE_HEADER && viewType != TYPE_TEXT;
            }

        }

        private static class TextHolder extends RecyclerView.ViewHolder {

            public TextHolder(View itemView) {
                super(itemView);
            }

            public void bind(int textResId) {
                ((TextView) itemView).setText(textResId);
            }

            public void bind(String text) {
                ((TextView) itemView).setText(text);
            }

        }

        private final class ServerHolder extends TextHolder implements View.OnClickListener {

            private static final int ACTION_ADD = 1;
            private static final int ACTION_SHOW_ALL = 2;

            ServerConfigData mServer;

            public ServerHolder(View itemView) {
                super(itemView);
                itemView.setOnClickListener(this);
            }

            public void bind(ServerConfigData server) {
                mServer = server;
                super.bind(server.name);
            }


            @Override
            public void onClick(View v) {
                mContext.openServer(mServer);
            }

        }

        private static class TextIconHolder extends RecyclerView.ViewHolder {

            private TextView mTextView;
            private ImageView mImageView;

            public TextIconHolder(View itemView) {
                super(itemView);
                mTextView = itemView.findViewById(R.id.text);
                mImageView = itemView.findViewById(R.id.icon);
            }

            public void bind(int textResId, int imageResId) {
                mTextView.setText(textResId);
                mImageView.setImageResource(imageResId);
            }

        }

        private final class ActionHolder extends TextIconHolder implements View.OnClickListener {

            private static final int ACTION_ADD = 1;
            private static final int ACTION_SHOW_ALL = 2;

            private int mActionType;

            public ActionHolder(View itemView) {
                super(itemView);
                itemView.setOnClickListener(this);
            }

            public void bind(int actionType) {
                mActionType = actionType;
                if (actionType == ACTION_ADD)
                    super.bind(R.string.add_server, R.drawable.ic_add_white);
                else if (actionType == ACTION_SHOW_ALL)
                    super.bind(R.string.irc_link_show_all, R.drawable.ic_sort_white);
            }


            @Override
            public void onClick(View v) {
                if (mActionType == ACTION_ADD) {
                    ArrayList<String> channels = new ArrayList<>();
                    channels.add(mChannelName);

                    Intent intent = new Intent(v.getContext(), EditServerActivity.class);
                    intent.putExtra(EditServerActivity.ARG_NAME, mHostName);
                    intent.putExtra(EditServerActivity.ARG_ADDRESS, mHostName);
                    intent.putExtra(EditServerActivity.ARG_AUTOJOIN_CHANNELS, channels);
                    mContext.startActivityForResult(intent, REQUEST_ADD_SERVER);
                }
                if (mActionType == ACTION_SHOW_ALL) {
                    reloadServerList(false);
                }
            }

        }

    }

}