//
//  KBFunctionView.m
//  CustomKeyboard
//
//  Created by Mac on 2025/10/28.
//

#import "KBFunctionView.h"
#import "KBResponderUtils.h" // 统一查找 UIInputViewController 的工具
#import "KBFunctionBarView.h"
#import "KBFunctionPasteView.h"
#import "KBFunctionTagCell.h"
#import "Masonry.h"
#import <MBProgressHUD.h>
#import "KBFullAccessGuideView.h"
#import "KBFullAccessManager.h"
#import "KBSkinManager.h"
#import "KBAuthManager.h"          // 登录态判断（共享钥匙串）
#import "KBULBridge.h"             // Darwin 通知常量（UL 已处理）
#import "KBURLOpenBridge.h" // 兜底从扩展侧直接尝试 openURL:
#import "KBStreamTextView.h"  // 流式文本视图
#import "KBStreamOverlayView.h" // 带关闭按钮的流式层
#import "KBFunctionTagListView.h"
#import "KBStreamFetcher.h"   // 网络流封装

@interface KBFunctionView () <KBFunctionBarViewDelegate, KBStreamOverlayViewDelegate, KBFunctionTagListViewDelegate>
// UI
@property (nonatomic, strong) KBFunctionBarView *barViewInternal;
@property (nonatomic, strong) KBFunctionPasteView *pasteViewInternal;
@property (nonatomic, strong) KBFunctionTagListView *tagListView;
@property (nonatomic, strong) UIView *rightButtonContainer; // 右侧竖排按钮容器
@property (nonatomic, strong) UIButton *pasteButtonInternal;
@property (nonatomic, strong) UIButton *deleteButtonInternal;
@property (nonatomic, strong) UIButton *clearButtonInternal;
@property (nonatomic, strong) UIButton *sendButtonInternal;

// 叠层：流式文本视图 + 关闭按钮
@property (nonatomic, strong, nullable) KBStreamOverlayView *streamOverlay;

// 网络流式（封装）
@property (nonatomic, strong, nullable) KBStreamFetcher *streamFetcher;
@property (nonatomic, assign) BOOL streamHasOutput; // 是否已输出过正文（首段去首个 \t 用）
@property (nonatomic, strong, nullable) NSNumber *loadingTagIndex; // 当前显示loading的标签index
@property (nonatomic, copy, nullable) NSString *loadingTagTitle;

// Data
@property (nonatomic, strong) NSArray<NSString *> *itemsInternal;

// 剪贴板自动检测
@property (nonatomic, strong) NSTimer *pasteboardTimer;    // 轮询定时器（轻量、主线程）
@property (nonatomic, assign) NSInteger lastHandledPBCount; // 上次处理过的 changeCount，避免重复弹窗

// UL 双路兜底
@property (nonatomic, assign) NSUInteger kb_ulSeq;      // 当前 UL 发起序号
@property (nonatomic, assign) BOOL kb_ulHandledFlag;    // 主 App 已确认处理 UL
@end

@implementation KBFunctionView

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // 背景使用当前主题强调色
        [self kb_applyTheme];

        [self setupUI];
        [self reloadDemoData];

        // 初始化剪贴板监控状态
        _lastHandledPBCount = [UIPasteboard generalPasteboard].changeCount;

        // 监听“完全访问”状态变化，动态启停剪贴板监控，避免在未开完全访问时触发 TCC/XPC 错误日志
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kb_fullAccessChanged) name:KBFullAccessChangedNotification object:nil];

        // 监听主 App 的 Darwin 确认（UL 已处理）
        CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
                                        (__bridge const void *)(self),
                                        KBULDarwinCallback,
                                        (__bridge CFStringRef)KBDarwinULHandled,
                                        NULL,
                                        CFNotificationSuspensionBehaviorDeliverImmediately);
    }
    return self;
}

#pragma mark - Theme

- (void)kb_applyTheme {
    KBSkinManager *mgr = [KBSkinManager shared];
    UIColor *accent = mgr.current.accentColor ?: [UIColor colorWithRed:0.77 green:0.93 blue:0.82 alpha:1.0];
    BOOL hasImg = ([mgr currentBackgroundImage] != nil);
    self.backgroundColor = hasImg ? [accent colorWithAlphaComponent:0.65] : accent;
}

- (void)dealloc {
    [self stopPasteboardMonitor];
    [self kb_stopNetworkStreaming];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void *)(self), (__bridge CFStringRef)KBDarwinULHandled, NULL);
}

#pragma mark - UI

- (void)setupUI {
    // 1. 顶部 Bar
    [self addSubview:self.barViewInternal];
    [self.barViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self);
        make.top.equalTo(self.mas_top).offset(6);
        make.height.mas_equalTo(48);
    }];

    // 右侧竖排按钮容器
    [self addSubview:self.rightButtonContainer];
    [self.rightButtonContainer mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.equalTo(self.mas_right).offset(-6);
        make.top.equalTo(self.barViewInternal.mas_bottom).offset(8);
        make.bottom.equalTo(self.mas_bottom).offset(-10);
        make.width.mas_equalTo(72);
    }];

    // 右侧四个按钮
    [self.rightButtonContainer addSubview:self.pasteButtonInternal];
    [self.rightButtonContainer addSubview:self.deleteButtonInternal];
    [self.rightButtonContainer addSubview:self.clearButtonInternal];
    [self.rightButtonContainer addSubview:self.sendButtonInternal];

    // 竖向排布：粘贴、删除、清空为等高；发送优先更高，但允许在空间不足时压缩
    CGFloat smallH = 44;
    CGFloat bigH = 56;
    // 原 10 在键盘总高度 276 下容易超出容器，改为 8 以避免 AutoLayout 冲突
    CGFloat vSpace = 8;
    [self.pasteButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.rightButtonContainer.mas_top);
        make.left.right.equalTo(self.rightButtonContainer);
        make.height.mas_equalTo(smallH);
    }];
    [self.deleteButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.pasteButtonInternal.mas_bottom).offset(vSpace);
        make.left.right.equalTo(self.rightButtonContainer);
        make.height.equalTo(self.pasteButtonInternal);
    }];
    [self.clearButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.deleteButtonInternal.mas_bottom).offset(vSpace);
        make.left.right.equalTo(self.rightButtonContainer);
        make.height.equalTo(self.pasteButtonInternal);
    }];
    [self.sendButtonInternal mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.clearButtonInternal.mas_bottom).offset(vSpace);
        make.left.right.equalTo(self.rightButtonContainer);
        // 允许在空间不足时缩短到 smallH，避免产生约束冲突
        make.height.greaterThanOrEqualTo(@(smallH));
        make.height.lessThanOrEqualTo(@(bigH));
        make.bottom.lessThanOrEqualTo(self.rightButtonContainer.mas_bottom);
    }];

    // 2. 粘贴区（位于右侧按钮左侧）
    [self addSubview:self.pasteViewInternal];
    [self.pasteViewInternal mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mas_left).offset(12);
        make.right.equalTo(self.rightButtonContainer.mas_left).offset(-12);
        make.top.equalTo(self.barViewInternal.mas_bottom).offset(8);
        make.height.mas_equalTo(48);
    }];

    // 3. Tag List View
    [self addSubview:self.tagListView];
    [self.tagListView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mas_left).offset(12);
        make.right.equalTo(self.rightButtonContainer.mas_left).offset(-12);
        make.top.equalTo(self.pasteViewInternal.mas_bottom).offset(10);
        make.bottom.equalTo(self.mas_bottom).offset(-10);
    }];
}

#pragma mark - Data

- (void)reloadDemoData {
    // 演示数据（可由外部替换）
    self.itemsInternal = @[@"高情商", @"暖味拉扯", @"风趣幽默", @"撩女生", @"社交惬匿", @"情场高手", @"一枚暖男", @"聊天搭子", @"表达爱意", @"更多话术"];    
    [self.tagListView setItems:self.itemsInternal];
}

// UICollectionView 逻辑已下沉至 KBFunctionTagListView

- (void)kb_showStreamTextViewIfNeededWithTitle:(NSString *)title {
    // 已有则不重复创建
    if (self.streamOverlay.superview) { return; }

    // 隐藏标签列表，使用同一区域展示流式文本
    self.tagListView.hidden = YES;

    KBStreamOverlayView *overlay = [[KBStreamOverlayView alloc] init];
    overlay.delegate = (id)self;
    [self addSubview:overlay];
    [overlay mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mas_left).offset(12);
        // 流式期间占满右侧宽度：不再贴 rightButtonContainer，让文本有最大宽度
        make.right.equalTo(self.mas_right).offset(-12);
        make.top.equalTo(self.pasteViewInternal.mas_bottom).offset(10);
        make.bottom.equalTo(self.mas_bottom).offset(-10);
    }];
    // 隐藏右侧按钮栏，最大化文本宽度；关闭 overlay 时再恢复
    self.rightButtonContainer.hidden = YES;
    // 适当缩小内部左右留白，进一步提升可用宽度
    overlay.textView.contentHorizontalPadding = 8.0;
    self.streamOverlay = overlay;

    // 只创建 UI；网络在点击 cell 时启动，避免重复 start 导致首包重复
}

- (void)kb_onTapStreamDelete {
    // 关闭并销毁流式视图，恢复标签列表
    [self kb_stopNetworkStreaming];
    [self.streamOverlay removeFromSuperview];
    self.streamOverlay = nil;
    self.tagListView.hidden = NO;
    // 恢复右侧按钮栏
    self.rightButtonContainer.hidden = NO;
}

// 叠层关闭回调
- (void)streamOverlayDidTapClose:(KBStreamOverlayView *)overlay {
    [self kb_onTapStreamDelete];
}


#pragma mark - Network Streaming (GET)

// 后端测试地址（内网）。若被 ATS 拦截，请在扩展 target 的 Info.plist 中允许 HTTP 或添加例外域。
static NSString * const kKBStreamDemoURL = @"http://192.168.1.144:7529/api/demo/talk";

- (void)kb_startNetworkStreamingWithSeed:(NSString *)seedTitle {
    [self kb_stopNetworkStreaming];
    if (![[KBFullAccessManager shared] hasFullAccess]) { return; }

    NSURL *url = [NSURL URLWithString:kKBStreamDemoURL];
    if (!url) { return; }

    self.streamHasOutput = NO; // 重置首段处理标记
    __weak typeof(self) weakSelf = self;
    KBStreamFetcher *fetcher = [KBStreamFetcher fetcherWithURL:url];
    // 由本类统一做 /t->\t 与首段去 \t，fetcher 只负责增量与协议解析
    fetcher.disableCompression = YES;
    fetcher.acceptEventStream = NO;  // 响应头若是 SSE 仍会自动解析
    // 将 \t 与首段去 \t 的处理下沉到 Fetcher，避免 UI 抖动
    fetcher.treatSlashTAsTab = YES;
    fetcher.trimLeadingTabOnce = YES;
    fetcher.flushInterval = 0.05; // 更接近“立刻显示”的节奏
    fetcher.onChunk = ^(NSString *chunk) {
        __strong typeof(weakSelf) self = weakSelf; if (!self) return;
        [self kb_appendChunkToStreamView:chunk];
    };
    fetcher.onFinish = ^(NSError * _Nullable error) {
        __strong typeof(weakSelf) self = weakSelf; if (!self) return;
        // 若还未出现任何数据且仍在 loading，则取消小菊花
        if (!self.streamHasOutput && self.loadingTagIndex) {
            [self.tagListView setLoading:NO atIndex:self.loadingTagIndex.integerValue];
            self.loadingTagIndex = nil; self.loadingTagTitle = nil;
        }
        if (error) { [KBHUD showInfo:@"拉取失败"]; }
        if (self.streamOverlay) { [self.streamOverlay finish]; }
    };
    self.streamFetcher = fetcher;
    [self.streamFetcher start];
}

- (void)kb_stopNetworkStreaming {
    [self.streamFetcher cancel];
    self.streamFetcher = nil;
    self.streamHasOutput = NO;
}

#pragma mark - Helpers

/// 统一处理需要输出到 KBStreamTextView 的分片：
/// - 目前网络层（KBStreamFetcher）已做 “/t->\t、首段去一个 \t、段间去一个空格”
/// - 这里仅负责附加到视图与标记首段状态，避免 UI 抖动
- (void)kb_appendChunkToStreamView:(NSString *)chunk {
    if (chunk.length == 0) return;
    // 第一次有数据才创建 overlay，并取消 cell 上的小菊花
    if (!self.streamOverlay) {
        [self kb_showStreamTextViewIfNeededWithTitle:self.loadingTagTitle ?: @""];
        if (self.loadingTagIndex) {
            [self.tagListView setLoading:NO atIndex:self.loadingTagIndex.integerValue];
            self.loadingTagIndex = nil; self.loadingTagTitle = nil;
        }
    }
    if (!self.streamOverlay) return;
    [self.streamOverlay appendChunk:chunk];
    self.streamHasOutput = YES;
}

#pragma mark - KBFunctionTagListViewDelegate

- (void)tagListView:(KBFunctionTagListView *)view didSelectIndex:(NSInteger)index title:(NSString *)title {
    // 1) 先判断权限：未开启“完全访问”则走引导逻辑
    if (![[KBFullAccessManager shared] hasFullAccess]) {
        // 未开启完全访问：保持原有引导路径
        [KBHUD showInfo:@"处理中…"];
        [[KBFullAccessManager shared] ensureFullAccessOrGuideInView:self];
        return;
    }

    // 2) 权限没问题，再判断是否登录：未登录 -> 直接拉起主 App，由主 App 负责完成登录
    if (!KBAuthManager.shared.isLoggedIn) {
        UIInputViewController *ivc = KBFindInputViewController(self);
        if (!ivc) return;
        NSString *encodedTitle = [title stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]] ?: @"";
        NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=functionView&index=%ld&title=%@", KB_UL_LOGIN, (long)index, encodedTitle]];
        if (!ul) return;
        // 发起 UL，不依赖 ok 结果
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [ivc.extensionContext openURL:ul completionHandler:^(__unused BOOL ok) {}];
        });
        // 双路兜底：500ms 内未收到主 App 确认，则回退到自定义 Scheme
        self.kb_ulHandledFlag = NO;
        NSUInteger token = ++self.kb_ulSeq;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (token != self.kb_ulSeq) return;      // 已有新请求覆盖
            if (self.kb_ulHandledFlag) return;       // 主 App 已确认处理
            NSURL *scheme = [NSURL URLWithString:[NSString stringWithFormat:@"%@://login?src=functionView&index=%ld&title=%@", KB_APP_SCHEME, (long)index, encodedTitle]];
            if (!scheme) return;
            [ivc.extensionContext openURL:scheme completionHandler:^(__unused BOOL ok2) {
                if (ok2) return;
                BOOL bridged = NO;
                @try {
                    #pragma clang diagnostic push
                    #pragma clang diagnostic ignored "-Wunguarded-availability"
                    bridged = [KBURLOpenBridge openURLViaResponder:scheme from:self];
                    #pragma clang diagnostic pop
                } @catch (__unused NSException *e) { bridged = NO; }
                if (!bridged) {
                    [KBHUD showInfo:@"请切换到主App完成登录"];
                }
            }];
        });
        return;
    }

    // 3) 已登录：开始业务逻辑（展示加载并拉取流式内容）
    [self.tagListView setLoading:YES atIndex:index];
    self.loadingTagIndex = @(index);
    self.loadingTagTitle = title ?: @"";
    [self kb_startNetworkStreamingWithSeed:self.loadingTagTitle];
    return;
}

// Darwin 回调：主 App 已处理 UL
static void KBULDarwinCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    KBFunctionView *self_ = (__bridge KBFunctionView *)observer;
    if (!self_) return;
    dispatch_async(dispatch_get_main_queue(), ^{ self_.kb_ulHandledFlag = YES; });
}

// 用户点击功能标签：优先 UL 拉起主App，失败再 Scheme；两次都失败则提示开启完全访问。
// 若已开启“完全访问”，则直接在键盘侧创建 KBStreamTextView，并在其右上角提供删除按钮关闭。
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    // 权限全部打开（键盘已启用 + 完全访问）。在扩展进程中仅需判断“完全访问”。
    if ([[KBFullAccessManager shared] hasFullAccess]) {
        NSString *title = (indexPath.item < self.itemsInternal.count) ? self.itemsInternal[indexPath.item] : @"";
        [self kb_showStreamTextViewIfNeededWithTitle:title];
        return;
    }

    [KBHUD showInfo:@"处理中…"];

    UIInputViewController *ivc = KBFindInputViewController(self);
    if (!ivc) return;

    NSString *title = (indexPath.item < self.itemsInternal.count) ? self.itemsInternal[indexPath.item] : @"";
    NSString *encodedTitle = [title stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]] ?: @"";

    NSURL *ul = [NSURL URLWithString:[NSString stringWithFormat:@"%@?src=functionView&index=%ld&title=%@", KB_UL_LOGIN, (long)indexPath.item, encodedTitle]];
    if (!ul) return;

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [ivc.extensionContext openURL:ul completionHandler:^(BOOL ok) {
            if (ok) return; // Universal Link 成功

            // 统一使用主 App 注册的自定义 Scheme
            NSURL *scheme = [NSURL URLWithString:[NSString stringWithFormat:@"%@@//login?src=functionView&index=%ld&title=%@", KB_APP_SCHEME, (long)indexPath.item, encodedTitle]];
            [ivc.extensionContext openURL:scheme completionHandler:^(BOOL ok2) {
                if (ok2) return;

                // 兜底：在用户点击触发的场景下，尝试通过响应链调用 openURL:
                // 以提升在“备忘录”等宿主中的成功率。
                BOOL bridged = NO;
                @try {
                    #pragma clang diagnostic push
                    #pragma clang diagnostic ignored "-Wunguarded-availability"
                    bridged = [KBURLOpenBridge openURLViaResponder:scheme from:self];
                    #pragma clang diagnostic pop
                } @catch (__unused NSException *e) { bridged = NO; }

                if (!bridged) {
                    // 两条路都失败：大概率未开完全访问或宿主拦截。统一交由 Manager 引导。
                    dispatch_async(dispatch_get_main_queue(), ^{ [[KBFullAccessManager shared] ensureFullAccessOrGuideInView:self]; });
                }
            }];
        }];
    });
}


#pragma mark - Button Actions

- (void)onTapPaste {
    // 用户点击“粘贴”时才读取剪贴板：
    // - iOS16+ 会在跨 App 首次读取时自动弹出系统权限弹窗；
    // - iOS15 及以下不会弹窗，直接返回内容；
    // 注意：不要在非用户触发的时机主动读取（如 viewDidLoad），否则会造成“立刻弹窗”的体验。
    UIPasteboard *pb = [UIPasteboard generalPasteboard];
    NSString *text = pb.string; // 读取纯文本（可能触发系统粘贴权限弹窗）

    if (text.length > 0) {
        // 将粘贴内容展示到左侧“粘贴区”的占位文案上
        self.pasteView.placeholderLabel.text = text;
        // 如果需要多行展示，可按需放开（高度由外部约束决定，默认一行会截断）
        // self.pasteView.placeholderLabel.numberOfLines = 0;
    } else {
        // 无可用文本或用户拒绝了粘贴权限；保持占位文案不变
        NSLog(@"粘贴板无可用文本或未授权粘贴");
    }
}

#pragma mark - 自动监控剪贴板（复制即弹窗）
// 说明：
// - 仅在视图可见时开启轮询，避免不必要的读取与打扰；
// - 当检测到 changeCount 变化，立即读 pasteboard.string：
//   * iOS16+：此处会触发系统“是否允许粘贴”弹窗；
//   * iOS15：不会弹窗，直接得到文本；
// - 无论允许/拒绝，都把本次 changeCount 记为已处理，避免一直重复询问。

- (void)startPasteboardMonitor {
    // 未开启“完全访问”时不做自动读取，避免宿主/系统拒绝并刷错误日志
    if (![[KBFullAccessManager shared] hasFullAccess]) return;
    if (self.pasteboardTimer) return;
    KBWeakSelf
    self.pasteboardTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        __strong typeof(weakSelf) self = weakSelf; if (!self) return;
        UIPasteboard *pb = [UIPasteboard generalPasteboard];
        NSInteger cc = pb.changeCount;
        if (cc <= self.lastHandledPBCount) return; // 没有新复制
        self.lastHandledPBCount = cc; // 标记已处理，避免重复

        // 实际读取触发系统弹窗（iOS16+）
        NSString *text = pb.string;
        if (text.length > 0) {
            self.pasteView.placeholderLabel.text = text;
        }
    }];
}

- (void)stopPasteboardMonitor {
    [self.pasteboardTimer invalidate];
    self.pasteboardTimer = nil;
}

- (void)didMoveToWindow {
    [super didMoveToWindow];
    [self kb_refreshPasteboardMonitor];
}

- (void)setHidden:(BOOL)hidden {
    BOOL wasHidden = self.isHidden;
    [super setHidden:hidden];
    if (wasHidden != hidden) {
        [self kb_refreshPasteboardMonitor];
    }
}

// 根据窗口可见性与完全访问状态，统一启停粘贴板监控
- (void)kb_refreshPasteboardMonitor {
    BOOL visible = (self.window && !self.isHidden);
    if (visible && [[KBFullAccessManager shared] hasFullAccess]) {
        [self startPasteboardMonitor];
    } else {
        [self stopPasteboardMonitor];
    }
}

- (void)kb_fullAccessChanged {
    dispatch_async(dispatch_get_main_queue(), ^{ [self kb_refreshPasteboardMonitor]; });
}
- (void)onTapDelete {
    NSLog(@"点击：删除");
    UIInputViewController *ivc = KBFindInputViewController(self);
    id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
    [proxy deleteBackward];
}
- (void)onTapClear {
    NSLog(@"点击：清空");
    // 连续删除：仅清空光标之前的输入（不改动 pasteView 的内容）
    UIInputViewController *ivc = KBFindInputViewController(self);
    id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
    // 逐批读取 documentContextBeforeInput 并删除，避免 50 字符窗口限制带来的残留
    NSInteger guard = 0; // 上限保护，避免极端情况下长时间阻塞
    while (guard < 10000) {
        NSString *before = proxy.documentContextBeforeInput ?: @"";
        NSInteger count = before.length;
        if (count <= 0) { break; } // 光标前已无内容
        for (NSInteger i = 0; i < count; i++) {
            [proxy deleteBackward];
        }
        guard += count;
    }
}
- (void)onTapSend {
    NSLog(@"点击：发送");
    // 发送：插入换行。大多数聊天类 App 会把回车视为“发送”
    UIInputViewController *ivc = KBFindInputViewController(self);
    id<UITextDocumentProxy> proxy = ivc.textDocumentProxy;
    [proxy insertText:@"\n"];
}

#pragma mark - Lazy

- (KBFunctionBarView *)barViewInternal {
    if (!_barViewInternal) {
        _barViewInternal = [[KBFunctionBarView alloc] init];
        _barViewInternal.delegate = self; // 顶部功能Bar事件下发到本View
    }
    return _barViewInternal;
}

#pragma mark - KBFunctionBarViewDelegate

- (void)functionBarView:(KBFunctionBarView *)bar didTapLeftAtIndex:(NSInteger)index {
    // 将事件继续透传给上层（如键盘控制器），用于切换界面或其它业务
    if ([self.delegate respondsToSelector:@selector(functionView:didTapToolActionAtIndex:)]) {
        [self.delegate functionView:self didTapToolActionAtIndex:index];
    }
}

- (void)functionBarView:(KBFunctionBarView *)bar didTapRightAtIndex:(NSInteger)index {
    // 右侧按钮点击，如收藏/宫格等，按需继续向外抛出（这里暂不定义单独协议方法，可在此内部处理或扩展）
}

- (KBFunctionPasteView *)pasteViewInternal {
    if (!_pasteViewInternal) {
        _pasteViewInternal = [[KBFunctionPasteView alloc] init];
    }
    return _pasteViewInternal;
}

- (KBFunctionTagListView *)tagListView {
    if (!_tagListView) {
        _tagListView = [[KBFunctionTagListView alloc] init];
        _tagListView.delegate = (id)self;
    }
    return _tagListView;
}

- (UIView *)rightButtonContainer {
    if (!_rightButtonContainer) {
        _rightButtonContainer = [[UIView alloc] init];
        _rightButtonContainer.backgroundColor = [UIColor clearColor];
    }
    return _rightButtonContainer;
}

- (UIButton *)buildRightButtonWithTitle:(NSString *)title color:(UIColor *)color {
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
    btn.backgroundColor = color;
    btn.layer.cornerRadius = 12.0;
    btn.layer.masksToBounds = YES;
    btn.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
    [btn setTitle:title forState:UIControlStateNormal];
    [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    return btn;
}

- (UIButton *)pasteButtonInternal {
    if (!_pasteButtonInternal) {
        _pasteButtonInternal = [self buildRightButtonWithTitle:@"粘贴" color:[UIColor colorWithRed:0.13 green:0.73 blue:0.60 alpha:1.0]];
        [_pasteButtonInternal addTarget:self action:@selector(onTapPaste) forControlEvents:UIControlEventTouchUpInside];
    }
    return _pasteButtonInternal;
}

- (UIButton *)deleteButtonInternal {
    if (!_deleteButtonInternal) {
        // 浅灰底深色文字，更接近截图里“删除”样式
        _deleteButtonInternal = [UIButton buttonWithType:UIButtonTypeSystem];
        _deleteButtonInternal.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
        _deleteButtonInternal.layer.cornerRadius = 12.0;
        _deleteButtonInternal.layer.masksToBounds = YES;
        _deleteButtonInternal.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
        [_deleteButtonInternal setTitle:@"删除" forState:UIControlStateNormal];
        [_deleteButtonInternal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [_deleteButtonInternal addTarget:self action:@selector(onTapDelete) forControlEvents:UIControlEventTouchUpInside];
    }
    return _deleteButtonInternal;
}

- (UIButton *)clearButtonInternal {
    if (!_clearButtonInternal) {
        _clearButtonInternal = [UIButton buttonWithType:UIButtonTypeSystem];
        _clearButtonInternal.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
        _clearButtonInternal.layer.cornerRadius = 12.0;
        _clearButtonInternal.layer.masksToBounds = YES;
        _clearButtonInternal.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
        [_clearButtonInternal setTitle:@"清空" forState:UIControlStateNormal];
        [_clearButtonInternal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [_clearButtonInternal addTarget:self action:@selector(onTapClear) forControlEvents:UIControlEventTouchUpInside];
    }
    return _clearButtonInternal;
}

- (UIButton *)sendButtonInternal {
    if (!_sendButtonInternal) {
        _sendButtonInternal = [self buildRightButtonWithTitle:@"发送" color:[UIColor colorWithRed:0.13 green:0.73 blue:0.60 alpha:1.0]];
        [_sendButtonInternal addTarget:self action:@selector(onTapSend) forControlEvents:UIControlEventTouchUpInside];
    }
    return _sendButtonInternal;
}


#pragma mark - Expose

- (UICollectionView *)collectionView { return self.tagListView.collectionView; }
- (NSArray<NSString *> *)items { return self.itemsInternal; }
- (KBFunctionBarView *)barView { return self.barViewInternal; }
- (KBFunctionPasteView *)pasteView { return self.pasteViewInternal; }
- (UIButton *)pasteButton { return self.pasteButtonInternal; }
- (UIButton *)deleteButton { return self.deleteButtonInternal; }
- (UIButton *)clearButton { return self.clearButtonInternal; }
- (UIButton *)sendButton { return self.sendButtonInternal; }

#pragma mark - Find Owner Controller

// 工具方法已提取到 KBResponderUtils.h

@end
