package com.kaixed.kchat.view.activity;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.IBinder;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.kaixed.kchat.database.ObjectBox;
import com.kaixed.kchat.database.UserManager;
import com.kaixed.kchat.database.entity.Messages;
import com.kaixed.kchat.database.entity.Messages_;
import com.kaixed.kchat.databinding.ActivityChatBinding;
import com.kaixed.kchat.service.WebSocketService;
import com.kaixed.kchat.utils.ConstantsUtil;
import com.kaixed.kchat.utils.ImageSpanUtil;
import com.kaixed.kchat.view.adapter.ChatAdapter;
import com.kaixed.kchat.view.adapter.EmojiAdapter;
import com.kaixed.kchat.view.adapter.FunctionPanelAdapter;
import com.kaixed.kchat.view.i.OnItemClickListener;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import io.objectbox.Box;
import io.objectbox.query.Query;
import io.objectbox.query.QueryBuilder;

/**
 * @author hui
 */
public class ChatActivity extends AppCompatActivity implements OnItemClickListener {

    private ChatAdapter chatAdapter;

    private WebSocketService webSocketService;

    private final LinkedList<Messages> messagesList = new LinkedList<>();

    public static final String TAG = "ChatActivity";

    private Box<Messages> messagesBox;

    private String friendId;

    private static final long LIMIT = 50L;

    private boolean isLoading = false;

    private boolean isHasHistory = false;

    private boolean isBound = false;

    private String username;

    private long tempIndex;

    private final Context mContext = this;

    private List<String> strings;

    private InputMethodManager imm;

    private ActivityChatBinding binding;

    private int softKeyboardHeight;

    private String contactId;

    private final ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            WebSocketService.LocalBinder binder = (WebSocketService.LocalBinder) service;
            webSocketService = binder.getService();
            isBound = true;
            observeLiveData();
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            isBound = false;
        }
    };

    private boolean isKeyboardShown = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        binding = ActivityChatBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        initData();
        initView();
        firstLoadData();

        setListener();

        handleIntent(getIntent());
        bindWebSocketService();

        imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        setPanelChange();

        setBackPressListener();

        getKeyBoardVisibility();

    }

    private void getKeyBoardVisibility() {
        final View rootView = findViewById(android.R.id.content);

        rootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
            Rect r = new Rect();
            rootView.getWindowVisibleDisplayFrame(r);
            int screenHeight = rootView.getRootView().getHeight();
            int keypadHeight = screenHeight - r.bottom;
            isKeyboardShown = keypadHeight > screenHeight * 0.15;
        });
    }

    private void setBackPressListener() {
        getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
            @Override
            public void handleOnBackPressed() {
                if (binding.clBottomPanel.isShown()) {
                    hidePanel(false);
                } else {
                    setEnabled(false);
                    onBackPressed();
                }
            }
        });
    }

    @SuppressLint("ClickableViewAccessibility")
    private void setPanelChange() {
        binding.etInput.setOnTouchListener((v, event) -> {
            if (event.getAction() == MotionEvent.ACTION_UP && binding.clBottomPanel.isShown()) {
                lockContentViewHeight();
                hidePanel(true);
                unlockContentViewHeight();
            }
            return false;
        });

        binding.ivFunctionPanel.setOnClickListener(v -> {
            if (binding.clBottomPanel.isShown()) {
                if (binding.rvEmoji.isShown()) {
                    handlePanelSwitch(false);
                } else {
                    hideBottomPanel();
                }
            } else {
                switchPanel(false);
            }
        });

        binding.ivEmoji.setOnClickListener(v -> {
            if (binding.clBottomPanel.isShown()) {
                if (binding.gvFunctionPanel.isShown()) {
                    handlePanelSwitch(true);
                } else {
                    hideBottomPanel();
                }
            } else {
                switchPanel(true);
            }
        });
    }

    private void switchPanel(boolean isSwitchToEmoji) {
        if (isKeyboardShown) {
            lockContentViewHeight();
            handlePanelSwitch(isSwitchToEmoji);
            unlockContentViewHeight();
        } else {
            handlePanelSwitch(isSwitchToEmoji);
        }
    }

    private void hideBottomPanel() {
        lockContentViewHeight();
        hidePanel(true);
        unlockContentViewHeight();
    }

    private void lockContentViewHeight() {
        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) binding.recycleChatList.getLayoutParams();
        layoutParams.height = binding.recycleChatList.getHeight();
        layoutParams.weight = 0f;
        binding.recycleChatList.setLayoutParams(layoutParams);
    }

    private void unlockContentViewHeight() {
        binding.recycleChatList.postDelayed(() -> {
            LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) binding.recycleChatList.getLayoutParams();
            layoutParams.weight = 1f;
            binding.recycleChatList.setLayoutParams(layoutParams);
        }, 200);
    }


    private void setSoftKeyboardVisibility(boolean isShowKeyboard) {
        if (isShowKeyboard) {
            binding.etInput.requestFocus();
            imm.showSoftInput(binding.etInput, 0);
        } else {
            imm.hideSoftInputFromWindow(binding.etInput.getWindowToken(), 0);
        }
    }

    private void handlePanelSwitch(boolean isEmojiPanel) {
        setSoftKeyboardVisibility(false);
        binding.clBottomPanel.setVisibility(View.VISIBLE);

        binding.rvEmoji.setVisibility(isEmojiPanel ? View.VISIBLE : View.INVISIBLE);
        binding.gvFunctionPanel.setVisibility(isEmojiPanel ? View.INVISIBLE : View.VISIBLE);
    }

    private void hidePanel(boolean showSoftKeyboard) {
        if (binding.clBottomPanel.isShown()) {
            binding.clBottomPanel.setVisibility(View.GONE);
            if (showSoftKeyboard) {
                setSoftKeyboardVisibility(true);
            }
        }
    }

    private void handleIntent(Intent intent) {
        if (intent != null) {
            if (intent.hasExtra("friendId")) {
                contactId = intent.getStringExtra("friendId");
                binding.tvContactName.setText(contactId);
            }
        }
    }


    private void setListener() {

        binding.tvContactName.setOnLongClickListener(v -> {
            Intent intent = new Intent(mContext, TestActivity.class);
            startActivity(intent);
            return false;
        });


        binding.gvFunctionPanel.setSelector(new ColorDrawable(Color.TRANSPARENT));

        binding.tvSend.setOnClickListener(v -> sendMessage());
        binding.recycleChatList.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                assert layoutManager != null;
                int firstVisiblePosition = layoutManager.findLastVisibleItemPosition();
                if (tempIndex == messagesList.get(firstVisiblePosition).getMsgLocalId() && isHasHistory && !isLoading) {
                    Log.d(TAG, "加载历史消息");
                    loadMoreMessages();
                }
            }
        });
        binding.ivBack.setOnClickListener(v -> finish());

        binding.tvContactName.setOnClickListener(v -> {
            Intent intentContactsDetail = new Intent(mContext, ContactsDetailActivity.class);
            startActivity(intentContactsDetail);
        });

        binding.ivMore.setOnClickListener(v -> {
            Intent intentChatDetail = new Intent(mContext, ChatDetailActivity.class);
            startActivity(intentChatDetail);
        });


        binding.etInput.addTextChangedListener(textWatcher);

        binding.etInput.setOnEditorActionListener((v, actionId, event) -> {
            if (actionId == EditorInfo.IME_ACTION_DONE ||
                    (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN)) {
                sendMessage();
                return true;
            }
            return false;
        });
    }

    private final TextWatcher textWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            boolean isInputEmpty = binding.etInput.getText().toString().isEmpty();
            binding.ivFunctionPanel.setVisibility(!isInputEmpty ? View.GONE : View.VISIBLE);
            binding.tvSend.setVisibility(isInputEmpty ? View.GONE : View.VISIBLE);
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    };

    private void setupFunctionPanel() {
        strings = new ArrayList<>();
        strings.add("[委屈]");
        EmojiAdapter mEmojiAdapter = new EmojiAdapter(strings);
        mEmojiAdapter.setOnItemClickListener(this);
        binding.rvEmoji.setAdapter(mEmojiAdapter);

        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 7);
        binding.rvEmoji.setLayoutManager(gridLayoutManager);

        List<String> strings1 = new ArrayList<>();
        strings1.add("haha");
        strings1.add("haha");
        strings1.add("haha");
        strings1.add("haha");
        strings1.add("haha");

        FunctionPanelAdapter functionPanelAdapter = new FunctionPanelAdapter(strings1, this);
        binding.gvFunctionPanel.setAdapter(functionPanelAdapter);

    }

    @Override
    public void onItemClick(int position) {
        runOnUiThread(() -> {
            Editable editable = binding.etInput.getText();
            // 获取当前光标位置
            int index = binding.etInput.getSelectionStart();
            // 获取将要插入的表情符号
            String emoji = strings.get(position);
            // 使用 ImageSpanUtil 插入表情符号
            ImageSpanUtil.insertEmoji(mContext, editable, (int) binding.etInput.getTextSize(), emoji, index);
            // 设置新的光标位置
            binding.etInput.setSelection(index + emoji.length());
        });
    }

    private void initView() {
        setupFunctionPanel();
        setRecycleView();
        if (contactId != null) {
            binding.tvContactName.setText(contactId);
        }
        setPanel();
    }

    private void setPanel() {
        ViewGroup.LayoutParams layoutParams = binding.clBottomPanel.getLayoutParams();
        layoutParams.height = softKeyboardHeight;
        binding.clBottomPanel.setLayoutParams(layoutParams);
    }


    private void initData() {
        messagesBox = ObjectBox.get().boxFor(Messages.class);
        username = UserManager.getInstance().getUsername();
        Intent intent = getIntent();
        friendId = intent.getStringExtra("friendId");
        softKeyboardHeight = ConstantsUtil.getKeyboardHeight();
    }


    private void setRecycleView() {
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setReverseLayout(true);
        binding.recycleChatList.setLayoutManager(layoutManager);
        chatAdapter = new ChatAdapter(this, messagesList);
        binding.recycleChatList.setAdapter(chatAdapter);
    }

    /**
     * 初次进入进行加载历史数据
     */
    private void firstLoadData() {
        List<Messages> messages = queryData(0, LIMIT + 1);
        if (!messages.isEmpty()) {
            int size = messages.size();
            if (size >= LIMIT) {
                isHasHistory = true;
            }
            if (isHasHistory) {
                List<Messages> messages1 = messages.subList(0, (int) LIMIT);
                messagesList.addAll(messages1);
                tempIndex = messagesList.get(messagesList.size() - 1).getMsgLocalId();
            } else {
                messagesList.addAll(messages);
            }
        }

    }

    private void loadMoreMessages() {
        if (isLoading) {
            return;
        }
        isLoading = true;

        List<Messages> newMessages = queryDataById(tempIndex, LIMIT + 1);
        int size = newMessages.size();
        tempIndex = newMessages.get(size - 1).getMsgLocalId();
        isHasHistory = size > LIMIT;

        if (!newMessages.isEmpty()) {
            List<Messages> messages;
            if (isHasHistory) {
                messages = newMessages.subList(1, (int) LIMIT + 1);
            } else {
                messages = newMessages.subList(1, newMessages.size());
            }

            int messagesSize = messagesList.size();

            messagesList.addAll(messagesSize, messages);
            chatAdapter.notifyItemRangeInserted(messagesSize, newMessages.size());
        }

        isLoading = false;
    }


    private void observeLiveData() {
        if (webSocketService == null) {
            return;
        }
        webSocketService.getLiveData().observe(this, new Observer<Messages>() {
            @Override
            public void onChanged(Messages messages) {
                if (!"ack".equals(messages.getType()) && !username.equals(messages.getSenderId())) {
                    if (messages.getMsgLocalId() != 0) {
                        return;
                    }
                    messagesList.addFirst(messages);
                    runOnUiThread(() -> {
                        chatAdapter.notifyItemInserted(0);
                        binding.recycleChatList.smoothScrollToPosition(0);
                    });
                }
            }
        });
    }

    private void sendMessage() {
        String message = binding.etInput.getText().toString().trim();

        Messages messages = new Messages();
        messages.setTakerId(friendId);
        messages.setSenderId(username);
        messages.setContent(message);
        messages.setStatus("normal");
        messages.setType("normal");
        messages.setTimestamp(System.currentTimeMillis());

        addData(messages);

        Long id = messagesBox.put(messages);

        JSONObject jsonObject = new JSONObject();
        JSONObject jsonObject2 = new JSONObject();
        try {
            jsonObject2.put("receiverId", friendId);
            jsonObject2.put("content", message);
            jsonObject2.put("msgLocalId", id);
            jsonObject.put("type", "single");
            jsonObject.put("body", jsonObject2);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        webSocketService.sendMessage(jsonObject.toString(),id);


        binding.etInput.setText("");
    }

    private void addData(Messages messages) {
        messagesList.addFirst(messages);
        chatAdapter.notifyItemInserted(0);
        binding.recycleChatList.smoothScrollToPosition(0);
    }


    @NonNull
    private List<Messages> queryData(long offset, long limit) {
        Query<Messages> query = messagesBox
                .query(Messages_.takerId.equal(friendId))
                .order(Messages_.timestamp, QueryBuilder.DESCENDING)
                .build();
        return query.find(offset, limit);
    }


    @NonNull
    private List<Messages> queryDataById(long msgLocalId, long limit) {
        Query<Messages> query = messagesBox
                .query(Messages_.takerId.equal(friendId))
                .lessOrEqual(Messages_.msgLocalId, msgLocalId)
                .order(Messages_.timestamp, QueryBuilder.DESCENDING)
                .build();
        int offset = 0;
        return query.find(offset, limit);
    }

    private void bindWebSocketService() {
        Intent serviceIntent = new Intent(this, WebSocketService.class);
        bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isBound) {
            unbindService(connection);
            isBound = false;
        }
    }
}