package com.efounder.pansoft.chat.emoji.widget;

import android.content.Context;
import android.text.Editable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;

import com.efounder.widget.skinview.JfSkinAppCompatEditText;


/**
 * 这个是我们目前聊天使用的输入框
 * use XhsEmotionsKeyboard(https://github.com/w446108264/XhsEmoticonsKeyboard)
 * author: yqs
 * @see com.efounder.widget.skinview.SkinCustomViewInflater
 */
public class EmoticonsEditText extends JfSkinAppCompatEditText {
    private Context context;
    // private List<EmoticonFilter> mFilterList;

    public EmoticonsEditText(Context context) {
        this(context, null);
    }

    public EmoticonsEditText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public EmoticonsEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        try {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        } catch (ArrayIndexOutOfBoundsException e) {
            setText(getText().toString());
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (oldh > 0 && onSizeChangedListener != null) {
            onSizeChangedListener.onSizeChanged(w, h, oldw, oldh);
        }
    }

    @Override
    public void setGravity(int gravity) {
        try {
            super.setGravity(gravity);
        } catch (ArrayIndexOutOfBoundsException e) {
            setText(getText().toString());
            super.setGravity(gravity);
        }
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        try {
            super.setText(text, type);
            //setTextColor(context.getResources().getColor(R.color.jfchatactivity_bottom_editext_text_color));

        } catch (ArrayIndexOutOfBoundsException e) {
            setText(text.toString());
        }
    }

    @Override
    protected final void onTextChanged(CharSequence arg0, int start, int lengthBefore, int after) {
        super.onTextChanged(arg0, start, lengthBefore, after);
//        if(mFilterList == null){
//            return;
//        }
//        for(EmoticonFilter emoticonFilter : mFilterList) {
//            emoticonFilter.filter(this, arg0, start, lengthBefore, after);
//        }
    }

//    public void addEmoticonFilter(EmoticonFilter emoticonFilter){
//        if(mFilterList == null){
//            mFilterList = new ArrayList<>();
//        }
//        mFilterList.add(emoticonFilter);
//    }
//
//    public void removedEmoticonFilter(EmoticonFilter emoticonFilter){
//        if(mFilterList != null && mFilterList.contains(emoticonFilter)){
//            mFilterList.remove(emoticonFilter);
//        }
//    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
            if (onBackKeyClickListener != null) {
                onBackKeyClickListener.onBackKeyClick();
            }
        }
        return super.onKeyPreIme(keyCode, event);
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    public interface OnBackKeyClickListener {
        void onBackKeyClick();
    }

    OnBackKeyClickListener onBackKeyClickListener;

    public void setOnBackKeyClickListener(OnBackKeyClickListener i) {
        onBackKeyClickListener = i;
    }

    public interface OnSizeChangedListener {
        void onSizeChanged(int w, int h, int oldw, int oldh);
    }

    OnSizeChangedListener onSizeChangedListener;

    public void setOnSizeChangedListener(OnSizeChangedListener i) {
        onSizeChangedListener = i;
    }

    public SpData[] getSpDatas() {
        Editable editable = getText();
        SpData[] spanneds = editable.getSpans(0, getText().length(), SpData.class);
        if (spanneds != null && spanneds.length > 0) {
            for (SpData spData : spanneds) {
                int start = editable.getSpanStart(spData);
                int end = editable.getSpanEnd(spData);
                spData.setEnd(end);
                spData.setStart(start);
            }
            sortSpans(spanneds, 0, spanneds.length - 1);
            return spanneds;
        } else {
            return new SpData[]{};
        }


    }

    private void sortSpans(SpData[] spDatas, int left, int right) {
        if (left >= right) {
            return;
        }
        int i = left;
        int j = right;
        SpData keySpan = spDatas[left];
        int key = spDatas[left].start;
        while (i < j) {
            while (i < j && key <= spDatas[j].start) {
                j--;
            }
            spDatas[i] = spDatas[j];
            while (i < j && key >= spDatas[i].start) {
                i++;
            }

            spDatas[j] = spDatas[i];
        }

        spDatas[i] = keySpan;
        sortSpans(spDatas, left, i - 1);
        sortSpans(spDatas, i + 1, right);

    }

    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        return new SpInputConnectionWrapper(super.onCreateInputConnection(outAttrs), true);
    }


    /**
     * 监听光标位置
     */
    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        super.onSelectionChanged(selStart, selEnd);
        SpData[] spDatas = getSpDatas();
        for (int i = 0; i < spDatas.length; i++) {
            SpData spData = spDatas[i];
            int startPosition = spData.start;
            int endPosition = spData.end;
            if (changeSelection(selStart, selEnd, startPosition, endPosition, false)) {
                return;
            }
        }
    }

    /**
     * 插入特殊字符串
     *
     * @param showContent 特殊字符串显示在文本框中的内容
     * @param rollBack    是否往前删除一个字符，因为@的时候可能留了一个字符在输入框里
     * @param customData  特殊字符串的数据结构
     * @param customSpan  特殊字符串的样式
     */
    public void insertSpecialStr(CharSequence showContent, boolean rollBack, Object customData,
                                 Object customSpan, int selectId) {
        insertSpecialStr(showContent, true, rollBack, customData, customSpan, selectId);
    }


    public void insertSpecialStr(CharSequence showContent, boolean needSpSpan, boolean rollBack,
                                 Object customData,
                                 Object customSpan,
                                 int selectId) {
        if (TextUtils.isEmpty(showContent)) {
            return;
        }
        int index = getSelectionStart();
        Editable editable = getText();
        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(editable);
        SpannableString spannableString = new SpannableString(showContent);
        if (needSpSpan) {
            SpData spData = new SpData();
            spData.setShowContent(showContent);
            spData.setCustomData(customData);
            spData.setUserId(selectId);
            spannableString
                    .setSpan(spData, 0, spannableString.length(),
                            SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
            if (customSpan != null) {
                spData.setCustomSpan(customSpan);
            }
        }
        if (customSpan != null) {
            spannableString
                    .setSpan(customSpan, 0, spannableString.length(),
                            SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
        if (rollBack) {
            spannableStringBuilder.delete(index - 1, index);
            index--;
        }
        spannableStringBuilder.insert(index, spannableString);
        //@之后加一个空格
        //spannableStringBuilder.append(" ");
        spannableStringBuilder.insert(index+spannableString.length()," ");

        setText(spannableStringBuilder);
        //+1 是把空格位置加上
        setSelection(index + spannableString.length() + 1);
    }

    /**
     * 加入一个新的@
     * @param showContent
     * @param selectId
     */
    public void insertOneAt(CharSequence showContent,int selectId) {

        int index = getSelectionStart();
        Editable editable = getText();
        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(editable);
        SpannableString spannableString = new SpannableString(showContent);
            SpData spData = new SpData();
            spData.setShowContent(showContent);
            spData.setCustomData(1);
            spData.setUserId(selectId);
            spannableString.setSpan(spData, 0, spannableString.length(),
                            SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);

        spannableStringBuilder.insert(index, spannableString);
        //@之后加一个空格
        spannableStringBuilder.insert(index+spannableString.length()," ");
        setText(spannableStringBuilder);
        //+1 是把空格位置加上
        setSelection(index + spannableString.length() + 1);
    }

    /**
     * 不让光标进入特殊字符串内部
     *
     * @param selStart      光标起点
     * @param selEnd        光标终点
     * @param startPosition 特殊字符串起点
     * @param endPosition   特殊字符串终点
     * @param toEnd         将光标放起点还是终点,暂时没用上,都是放起点
     */
    private boolean changeSelection(int selStart, int selEnd, int startPosition, int endPosition,
                                    boolean toEnd) {
        boolean hasChange = false;
        if (selStart == selEnd) {
            if (startPosition != -1 && startPosition < selStart && selStart < endPosition) {
                if (toEnd) {
                    setSelection(endPosition);
                } else {
                    setSelection(startPosition);
                }
                hasChange = true;
            }
        } else {
            if (startPosition != -1 && startPosition < selStart && selStart < endPosition) {
                if (toEnd) {
                    setSelection(endPosition, selEnd);
                } else {
                    setSelection(startPosition, selEnd);
                }

                hasChange = true;
            }
            if (endPosition != -1 && startPosition < selEnd && selEnd < endPosition) {
                setSelection(selStart, endPosition);
                hasChange = true;
            }
        }
        return hasChange;
    }

    private boolean onDeleteEvent() {
        int selectionStart = getSelectionStart();
        final int selectionEnd = getSelectionEnd();
        if (selectionEnd != selectionStart) {
            return false;
        }
        SpData[] spDatas = getSpDatas();
        for (int i = 0; i < spDatas.length; i++) {
            SpData spData = spDatas[i];
            if (selectionStart == spData.end) {
                Editable editable = getText();
//        if ((editable.length() - spData.end) > 15) {
//          SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(editable);
//          spannableStringBuilder.delete(rangeStart, selectionEnd);
//          GifTextUtil.setText(SpEditText.this, spannableStringBuilder);
//          setSelection(rangeStart);
//        } else {
//          editable.delete(spData.start, spData.end);
//        }
                editable.delete(spData.start, spData.end);
                return true;
            }

        }
        return false;
    }

    private boolean onDpadRightEvent() {
        int selectionStart = getSelectionStart();
        int selectionEnd = getSelectionEnd();
        if (selectionEnd != selectionStart) {
            return false;
        }
        SpData[] spDatas = getSpDatas();
        for (int i = 0; i < spDatas.length; i++) {
            SpData spData = spDatas[i];
            if (selectionStart == spData.start) {
                setSelection(spData.end, spData.end);
                return true;
            }
        }
        return false;
    }


    public  static class SpData {

        /**
         * EditText中显示的内容
         */
        private CharSequence showContent;
        /**
         * 特殊内容的数据结构
         */
        private Object customData;
        private Object customSpan;
        /**
         * 提及的用户id
         **/
        private int userId;
        private int start;
        private int end;

        public int getUserId() {
            return userId;
        }

        public void setUserId(int userId) {
            this.userId = userId;
        }

        public Object getCustomSpan() {
            return customSpan;
        }

        private void setCustomSpan(Object customSpan) {
            this.customSpan = customSpan;
        }

        public int getStart() {
            return start;
        }

        private void setStart(int start) {
            this.start = start;
        }

        public int getEnd() {
            return end;
        }

        private void setEnd(int end) {
            this.end = end;
        }

        public Object getCustomData() {
            return customData;
        }

        private void setCustomData(Object customData) {
            this.customData = customData;
        }

        public CharSequence getShowContent() {
            return showContent;
        }

        private void setShowContent(CharSequence showContent) {
            this.showContent = showContent;
        }

        @Override
        public String toString() {
            return "SpData{" +
                    "showContent='" + showContent + '\'' +
                    ", customData=" + customData +
                    ", start=" + start +
                    ", end=" + end +
                    '}';
        }
    }

    private class SpInputConnectionWrapper extends InputConnectionWrapper {


        /**
         * Initializes a wrapper.
         * <p>
         * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
         * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
         * has {@code null} in {@code target}.</p>
         *
         * @param target  the {@link InputConnection} to be proxied.
         * @param mutable set {@code true} to protect this object from being reconfigured to target
         *                another {@link InputConnection}.  Note that this is ignored while the target is {@code
         *                null}.
         */
        public SpInputConnectionWrapper(InputConnection target, boolean mutable) {
            super(target, mutable);
        }


        @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
            boolean result = false;
            if (beforeLength == 1 && afterLength == 0) {
                result = onDeleteEvent();
            }
            return result || super.deleteSurroundingText(beforeLength, afterLength);
        }

        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            boolean result = false;
            if (event.getKeyCode() == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                result = onDeleteEvent();
            }
            if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT
                    && event.getAction() == KeyEvent.ACTION_DOWN) {
                result = onDpadRightEvent();
            }
            return result || super.sendKeyEvent(event);

        }
    }
}