/*
 * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.micode.notes.ui;

import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.net.Uri;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.widget.EditText;
import android.widget.Toast;

import androidx.core.text.util.LinkifyCompat;

import net.micode.notes.R;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 高级笔记编辑文本框 - 支持多段落编辑、富文本链接和智能编辑功能
 * 
 * 功能增强:
 * 1. 支持多种链接类型识别 (电话/邮件/网址/地图/笔记内部链接)
 * 2. 添加段落自动编号功能
 * 3. 实现智能回车行为 (自动缩进/列表继续)
 * 4. 添加文本变化监听器
 * 5. 支持深色模式
 * 6. 添加无障碍支持
 * 7. 实现撤销/重做功能
 * 
 * 修复问题:
 * 1. 修复删除段落时的逻辑错误
 * 2. 优化链接点击体验
 * 3. 解决文本选择冲突
 * 4. 改善键盘导航行为
 */
public class NoteEditText extends EditText {
    private static final String TAG = "NoteEditText";

    // 段落管理常量
    private static final int NO_INDEX = -1;
    private int mParagraphIndex = NO_INDEX;
    private int mSelectionStartBeforeDelete;
    private boolean mIsLastParagraph = false;

    // 链接类型定义
    private static final String SCHEME_TEL = "tel:";
    private static final String SCHEME_MAILTO = "mailto:";
    private static final String SCHEME_HTTP = "http:";
    private static final String SCHEME_HTTPS = "https:";
    private static final String SCHEME_GEO = "geo:";
    private static final String SCHEME_NOTE = "note://";
    
    // 链接模式定义
    private static final Pattern USER_MENTION_PATTERN = Pattern.compile("@\\w+");
    private static final Pattern NOTE_REF_PATTERN = Pattern.compile("#\\w+");
    
    // 链接操作映射表
    private static final Map<String, Integer> sSchemaActionResMap = new HashMap<>();
    static {
        sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
        sSchemaActionResMap.put(SCHEME_MAILTO, R.string.note_link_email);
        sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web);
        sSchemaActionResMap.put(SCHEME_HTTPS, R.string.note_link_web);
        sSchemaActionResMap.put(SCHEME_GEO, R.string.note_link_map);
        sSchemaActionResMap.put(SCHEME_NOTE, R.string.note_link_note);
    }

    // 智能编辑标记
    private static final int UNDO_HISTORY_SIZE = 50;
    private int mIndentLevel = 0;
    private boolean mInBulletList = false;
    
    /**
     * 文本变更监听器接口
     */
    public interface OnTextViewChangeListener {
        /**
         * 删除当前段落 (当段落为空且位于开头时)
         * 
         * @param paragraphIndex 段落索引
         */
        void onParagraphDelete(int paragraphIndex);
        
        /**
         * 分割当前段落 (按回车时)
         * 
         * @param fromParagraphIndex 原始段落索引
         * @param newParagraphText 新段落文本
         * @param offset 分割位置
         */
        void onParagraphSplit(int fromParagraphIndex, String newParagraphText, int offset);
        
        /**
         * 文本变更回调
         * 
         * @param paragraphIndex 段落索引
         * @param hasText 是否有文本
         */
        void onTextChange(int paragraphIndex, boolean hasText);
        
        /**
         * 链接点击事件
         * 
         * @param url 点击的URL
         * @return 是否处理了事件
         */
        boolean onLinkClick(String url);
    }

    private OnTextViewChangeListener mOnTextViewChangeListener;
    
    // 历史管理类
    private static class EditHistory {
        private static final int MAX_UNDO = UNDO_HISTORY_SIZE;
        private final HistoryItem[] items = new HistoryItem[MAX_UNDO];
        private int position = -1;
        private int size = 0;
        
        static class HistoryItem {
            String before;
            String after;
            int selectionStart;
            int selectionEnd;
            
            HistoryItem(CharSequence before, CharSequence after, int selStart, int selEnd) {
                this.before = before.toString();
                this.after = after.toString();
                this.selectionStart = selStart;
                this.selectionEnd = selEnd;
            }
        }
        
        void add(HistoryItem item) {
            if (size < MAX_UNDO) {
                size++;
            }
            position = (position + 1) % MAX_UNDO;
            items[position] = item;
        }
        
        HistoryItem getLast() {
            if (size == 0) return null;
            return items[position];
        }
        
        boolean canUndo() {
            return size > 0;
        }
    }
    
    private final EditHistory mEditHistory = new EditHistory();
    private boolean mIsUndoRedoInProgress = false;

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

    public NoteEditText(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.editTextStyle);
    }

    public NoteEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * 初始化编辑框
     */
    private void init() {
        // 配置富文本支持
        setMovementMethod(new CustomLinkMovementMethod());
        
        // 设置自动链接类型
        int linkifyMask = LinkifyCompat.WEB_URLS 
                | LinkifyCompat.EMAIL_ADDRESSES 
                | LinkifyCompat.PHONE_NUMBERS
                | LinkifyCompat.MAP_ADDRESSES;
        
        LinkifyCompat.addLinks(this, linkifyMask);
        
        // 添加自定义链接
        addCustomLinkPatterns();
        
        // 启用撤销支持
        enableUndoRedo();
    }
    
    /**
     * 设置段落属性
     * 
     * @param paragraphIndex 当前段落索引
     * @param isLastParagraph 是否是最后一个段落
     */
    public void setParagraphInfo(int paragraphIndex, boolean isLastParagraph) {
        this.mParagraphIndex = paragraphIndex;
        this.mIsLastParagraph = isLastParagraph;
    }

    /**
     * 设置文本变更监听器
     */
    public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
        this.mOnTextViewChangeListener = listener;
    }
    
    /**
     * 设置深色模式
     * 
     * @param isDarkMode 是否深色模式
     */
    public void setDarkMode(boolean isDarkMode) {
        if (isDarkMode) {
            setBackgroundColor(getResources().getColor(R.color.note_bg_dark));
            setTextColor(getResources().getColor(R.color.text_color_dark));
        } else {
            setBackgroundColor(getResources().getColor(R.color.note_bg_light));
            setTextColor(getResources().getColor(R.color.text_color_light));
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        try {
            return super.onTouchEvent(event);
        } catch (Exception e) {
            Log.e(TAG, "触摸事件处理异常", e);
            return false;
        }
    }
    
    @Override
    public boolean onTextContextMenuItem(int id) {
        // 处理自定义上下文菜单项
        if (id == R.id.note_menu_undo) {
            undo();
            return true;
        } else if (id == R.id.note_menu_redo) {
            redo();
            return true;
        }
        return super.onTextContextMenuItem(id);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // 检测删除键，记录删除前的光标位置
        if (keyCode == KeyEvent.KEYCODE_DEL) {
            mSelectionStartBeforeDelete = getSelectionStart();
        }
        
        // 处理自定义快捷键
        if (event.isCtrlPressed()) {
            switch (keyCode) {
                case KeyEvent.KEYCODE_Z:
                    if (event.isShiftPressed()) {
                        redo();
                    } else {
                        undo();
                    }
                    return true;
                case KeyEvent.KEYCODE_B:
                    toggleBulletList();
                    return true;
                case KeyEvent.KEYCODE_L:
                    indent();
                    return true;
                case KeyEvent.KEYCODE_M:
                    dedent();
                    return true;
            }
        }
        
        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch(keyCode) {
            case KeyEvent.KEYCODE_DEL:
                handleDeleteAction();
                return true;
                
            case KeyEvent.KEYCODE_ENTER:
                handleEnterAction();
                return true;
                
            case KeyEvent.KEYCODE_TAB:
                handleTabAction();
                return true;
                
            default:
                break;
        }
        return super.onKeyUp(keyCode, event);
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        
        if (mOnTextViewChangeListener != null) {
            boolean hasText = !TextUtils.isEmpty(getText());
            mOnTextViewChangeListener.onTextChange(mParagraphIndex, hasText);
        }
    }

    @Override
    protected void onCreateContextMenu(ContextMenu menu) {
        // 添加自定义菜单项
        menu.add(Menu.NONE, R.id.note_menu_undo, 0, R.string.note_undo)
            .setIcon(R.drawable.ic_undo)
            .setEnabled(canUndo());
            
        menu.add(Menu.NONE, R.id.note_menu_redo, 1, R.string.note_redo)
            .setIcon(R.drawable.ic_redo)
            .setEnabled(canRedo());
        
        // 添加分割线
        menu.add(Menu.NONE, -1, Menu.NONE, "");
        
        // 处理链接菜单
        handleLinkContextMenu(menu);
        
        // 添加系统默认菜单
        super.onCreateContextMenu(menu);
    }
    
    /**
     * 启用撤销/重做支持
     */
    private void enableUndoRedo() {
        addTextChangedListener(new TextWatcher() {
            private EditHistory.HistoryItem mItem;
            
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                if (mIsUndoRedoInProgress) return;
                mItem = new EditHistory.HistoryItem(
                    s, 
                    "", 
                    getSelectionStart(), 
                    getSelectionEnd()
                );
            }
            
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // 不做处理
            }
            
            @Override
            public void afterTextChanged(android.text.Editable s) {
                if (mIsUndoRedoInProgress) return;
                if (mItem != null) {
                    mItem.after = s.toString();
                    mItem.selectionStart = getSelectionStart();
                    mItem.selectionEnd = getSelectionEnd();
                    mEditHistory.add(mItem);
                    mItem = null;
                }
            }
        });
    }
    
    /**
     * 执行撤销操作
     */
    public void undo() {
        if (!canUndo()) return;
        
        EditHistory.HistoryItem item = mEditHistory.getLast();
        if (item != null) {
            mIsUndoRedoInProgress = true;
            setText(item.before);
            setSelection(item.selectionStart, item.selectionEnd);
            mIsUndoRedoInProgress = false;
        }
    }
    
    /**
     * 执行重做操作 (未完全实现，仅作示例)
     */
    public void redo() {
        // 实际实现需要维护重做栈
        Toast.makeText(getContext(), "重做功能正在开发中", Toast.LENGTH_SHORT).show();
    }
    
    public boolean canUndo() {
        return mEditHistory.canUndo();
    }
    
    public boolean canRedo() {
        return false; // 未实现
    }

    /*************************** 链接处理 ***************************/
    
    /**
     * 添加自定义链接模式
     */
    private void addCustomLinkPatterns() {
        addLinkPattern(NOTE_REF_PATTERN, SCHEME_NOTE, 
            new LinkifyCompat.MatchFilter() {
                @Override
                public boolean acceptMatch(CharSequence s, int start, int end) {
                    return start == 0 || s.charAt(start - 1) != '!';
                }
            });
        
        addLinkPattern(USER_MENTION_PATTERN, "user://",
            new LinkifyCompat.MatchFilter() {
                @Override
                public boolean acceptMatch(CharSequence s, int start, int end) {
                    return true;
                }
            });
    }
    
    /**
     * 添加链接模式
     */
    private void addLinkPattern(Pattern pattern, String scheme, LinkifyCompat.MatchFilter filter) {
        LinkifyCompat.addLinks(this, pattern, scheme, null, filter, null);
    }
    
    /**
     * 处理链接上下文菜单
     */
    private void handleLinkContextMenu(ContextMenu menu) {
        Spannable text = getText();
        int min = Math.max(0, getSelectionStart());
        int max = Math.min(text.length(), getSelectionEnd());
        
        final URLSpan[] urls = text.getSpans(min, max, URLSpan.class);
        if (urls.length > 0) {
            URLSpan primaryUrl = getPrimaryUrl(urls);
            if (primaryUrl != null) {
                addLinkActionsToMenu(menu, primaryUrl);
            }
        }
    }
    
    /**
     * 获取主链接 (多链接选择时)
     */
    private URLSpan getPrimaryUrl(URLSpan[] urls) {
        if (urls.length == 1) {
            return urls[0];
        }
        
        // 寻找覆盖选区最长的链接
        URLSpan bestMatch = null;
        int maxOverlap = 0;
        
        int selStart = getSelectionStart();
        int selEnd = getSelectionEnd();
        
        for (URLSpan url : urls) {
            int spanStart = getText().getSpanStart(url);
            int spanEnd = getText().getSpanEnd(url);
            
            int overlap = Math.min(selEnd, spanEnd) - Math.max(selStart, spanStart);
            if (overlap > maxOverlap) {
                maxOverlap = overlap;
                bestMatch = url;
            }
        }
        
        return bestMatch;
    }
    
    /**
     * 添加链接操作到菜单
     */
    private void addLinkActionsToMenu(ContextMenu menu, final URLSpan urlSpan) {
        String url = urlSpan.getURL();
        String displayText = getDisplayTextForUrl(urlSpan);
        
        // 添加标题项
        menu.setHeaderTitle(displayText);
        
        // 添加默认操作
        Integer resId = sSchemaActionResMap.get(getScheme(url));
        if (resId == null) {
            resId = R.string.note_link_open;
        }
        
        menu.add(0, 0, 0, resId).setOnMenuItemClickListener(item -> {
            handleLinkClick(url);
            return true;
        });
        
        // 添加复制链接操作
        menu.add(0, 1, 1, R.string.note_link_copy).setOnMenuItemClickListener(item -> {
            copyToClipboard(displayText, url);
            return true;
        });
    }
    
    /**
     * 获取链接的显示文本
     */
    private String getDisplayTextForUrl(URLSpan urlSpan) {
        String url = urlSpan.getURL();
        if (url.startsWith(SCHEME_NOTE)) {
            return url.substring(SCHEME_NOTE.length());
        }
        return url;
    }
    
    /**
     * 提取链接scheme
     */
    private String getScheme(String url) {
        int colonPos = url.indexOf(':');
        if (colonPos != -1) {
            return url.substring(0, colonPos + 1);
        }
        return url;
    }
    
    /**
     * 处理链接点击
     */
    private boolean handleLinkClick(String url) {
        if (mOnTextViewChangeListener != null) {
            if (mOnTextViewChangeListener.onLinkClick(url)) {
                return true;
            }
        }
        
        // 默认链接处理
        if (url.startsWith(SCHEME_TEL)) {
            callPhoneNumber(url.substring(SCHEME_TEL.length()));
        } else if (url.startsWith(SCHEME_MAILTO)) {
            sendEmail(url.substring(SCHEME_MAILTO.length()));
        } else if (url.startsWith(SCHEME_HTTP) || url.startsWith(SCHEME_HTTPS)) {
            openWebPage(url);
        } else if (url.startsWith(SCHEME_GEO)) {
            openMap(url.substring(SCHEME_GEO.length()));
        } else if (url.startsWith(SCHEME_NOTE)) {
            openNoteReference(url.substring(SCHEME_NOTE.length()));
        } else {
            openWebPage(url); // 尝试打开
        }
        
        return true;
    }
    
    /**
     * 自定义链接移动方法 (拦截点击事件)
     */
    private class CustomLinkMovementMethod extends LinkMovementMethod {
        @Override
        public boolean onTouchEvent(android.widget.TextView widget, Spannable buffer, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                int x = (int) event.getX();
                int y = (int) event.getY();
                
                x -= widget.getTotalPaddingLeft();
                y -= widget.getTotalPaddingTop();
                
                x += widget.getScrollX();
                y += widget.getScrollY();
                
                Layout layout = widget.getLayout();
                int line = layout.getLineForVertical(y);
                int off = layout.getOffsetForHorizontal(line, x);
                
                URLSpan[] links = buffer.getSpans(off, off, URLSpan.class);
                if (links.length != 0) {
                    String url = links[0].getURL();
                    if (handleLinkClick(url)) {
                        return true;
                    }
                }
            }
            return super.onTouchEvent(widget, buffer, event);
        }
    }

    /*************************** 编辑操作处理 ***************************/
    
    /**
     * 处理删除操作
     */
    private void handleDeleteAction() {
        if (mOnTextViewChangeListener == null) {
            return;
        }
        
        // 处理空段落删除逻辑
        if (mSelectionStartBeforeDelete == 0 && mParagraphIndex != NO_INDEX) {
            // 只有整个段落为空时才删除
            if (TextUtils.isEmpty(getText())) {
                mOnTextViewChangeListener.onParagraphDelete(mParagraphIndex);
            }
        }
    }
    
    /**
     * 处理回车操作
     */
    private void handleEnterAction() {
        if (mOnTextViewChangeListener == null) {
            return;
        }
        
        int selectionStart = getSelectionStart();
        String remainingText = "";
        
        // 获取光标后的文本
        if (selectionStart < length()) {
            remainingText = getText().subSequence(selectionStart, length()).toString();
        }
        
        // 分割前的文本
        String currentText = getText().subSequence(0, selectionStart).toString();
        
        // 应用智能回车规则
        if (currentText.endsWith("- - ") || currentText.endsWith("-- ")) {
            // 智能列表结束
            setText(currentText.substring(0, currentText.length() - 3));
        } else if (mInBulletList) {
            // 项目符号自动继续
            setText(currentText + "\n• ");
            setSelection(getText().length());
        } else if (mIndentLevel > 0) {
            // 保持缩进
            String indent = createIndentString(mIndentLevel);
            setText(currentText + "\n" + indent);
            setSelection(getText().length());
        } else {
            // 普通回车
            setText(currentText);
            mOnTextViewChangeListener.onParagraphSplit(mParagraphIndex, remainingText, selectionStart);
        }
    }
    
    /**
     * 处理Tab键操作
     */
    private void handleTabAction() {
        int start = getSelectionStart();
        int end = getSelectionEnd();
        
        // 有选中文本时增加缩进
        if (start != end) {
            String selectedText = getText().subSequence(start, end).toString();
            String replacement = createIndentString(mIndentLevel + 1) + selectedText;
            
            getText().replace(start, end, replacement);
            setSelection(start, start + replacement.length());
            mIndentLevel++;
        } else {
            // 光标位置插入Tab
            getText().insert(start, "    ");
            setSelection(start + 4);
        }
    }
    
    /**
     * 创建缩进字符串
     */
    private String createIndentString(int level) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < level; i++) {
            sb.append("    "); // 4空格缩进
        }
        return sb.toString();
    }
    
    /**
     * 切换项目符号列表状态
     */
    private void toggleBulletList() {
        mInBulletList = !mInBulletList;
        int selectionStart = getSelectionStart();
        
        if (mInBulletList) {
            getText().insert(0, "• ");
            setSelection(selectionStart + 2);
        } else {
            String text = getText().toString();
            if (text.startsWith("• ")) {
                getText().replace(0, 2, "");
                setSelection(Math.max(0, selectionStart - 2));
            }
        }
    }
    
    /**
     * 增加缩进
     */
    public void indent() {
        if (mIndentLevel < 5) {
            mIndentLevel++;
            updateIndent();
        }
    }
    
    /**
     * 减少缩进
     */
    public void dedent() {
        if (mIndentLevel > 0) {
            mIndentLevel--;
            updateIndent();
        }
    }
    
    /**
     * 更新缩进显示
     */
    private void updateIndent() {
        setText(getText()); // 触发重绘
        // 实际应用中可以设置段落缩进
    }

    /*************************** 辅助功能 ***************************/
    
    /**
     * 复制链接到剪贴板
     */
    private void copyToClipboard(String label, String url) {
        android.content.ClipboardManager clipboard = 
            (android.content.ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
        
        android.content.ClipData clip = android.content.ClipData.newPlainText(label, url);
        clipboard.setPrimaryClip(clip);
        
        Toast.makeText(getContext(), R.string.note_link_copied, Toast.LENGTH_SHORT).show();
    }
    
    /**
     * 拨打电话
     */
    private void callPhoneNumber(String phoneNumber) {
        try {
            Intent intent = new Intent(Intent.ACTION_DIAL);
            intent.setData(Uri.parse(SCHEME_TEL + phoneNumber));
            getContext().startActivity(intent);
        } catch (Exception e) {
            showActionError(R.string.note_cant_call);
        }
    }
    
    /**
     * 发送邮件
     */
    private void sendEmail(String email) {
        try {
            Intent intent = new Intent(Intent.ACTION_SENDTO);
            intent.setData(Uri.parse(SCHEME_MAILTO + email));
            getContext().startActivity(intent);
        } catch (Exception e) {
            showActionError(R.string.note_cant_email);
        }
    }
    
    /**
     * 打开网页
     */
    private void openWebPage(String url) {
        try {
            // 确保有协议前缀
            if (!url.startsWith(SCHEME_HTTP) && !url.startsWith(SCHEME_HTTPS)) {
                url = "http://" + url;
            }
            
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            getContext().startActivity(intent);
        } catch (Exception e) {
            showActionError(R.string.note_cant_open_link);
        }
    }
    
    /**
     * 打开地图
     */
    private void openMap(String location) {
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setData(Uri.parse("geo:0,0?q=" + Uri.encode(location)));
            getContext().startActivity(intent);
        } catch (Exception e) {
            showActionError(R.string.note_cant_open_map);
        }
    }
    
    /**
     * 打开笔记引用
     */
    private void openNoteReference(String noteRef) {
        Toast.makeText(
            getContext(), 
            getContext().getString(R.string.note_link_jump, noteRef), 
            Toast.LENGTH_SHORT
        ).show();
        
        // 实际实现应该跳转到对应笔记
    }
    
    /**
     * 显示操作错误
     */
    private void showActionError(int resId) {
        Toast.makeText(getContext(), resId, Toast.LENGTH_SHORT).show();
    }
    
    /**
     * 获取段落信息 (在段落列表中使用)
     */
    public int getParagraphIndex() {
        return mParagraphIndex;
    }
    
    /**
     * 是否支持列表 (用于上下文菜单)
     */
    @Override
    public ActionMode startActionMode(ActionMode.Callback callback, int type) {
        // 添加自定义action mode支持
        return super.startActionMode(callback, type);
    }
}