package com.bokecc.livemodule.live.room;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import androidx.core.math.MathUtils;
import com.bokecc.dwlivedemo.R;
import com.kuaishou.akdanmaku.DanmakuConfig;
import com.kuaishou.akdanmaku.data.DanmakuItem;
import com.kuaishou.akdanmaku.data.DanmakuItemData;
import com.kuaishou.akdanmaku.render.DanmakuRenderer;
import com.kuaishou.akdanmaku.ui.DanmakuDisplayer;
import com.kuaishou.akdanmaku.utils.Size;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 包含表情的弹幕渲染器
 */
public class CCLiveDanmakuRenderer implements DanmakuRenderer {
    private Context mContext;
    private static int ELEMENT_SPACE = 20;


    public CCLiveDanmakuRenderer(Context context) {
        this.mContext = context;
    }

    public static final Integer[] imgs = new Integer[]{
            R.drawable.em2_01, R.drawable.em2_02, R.drawable.em2_03, R.drawable.em2_04, R.drawable.em2_05, R.drawable.em2_06,
            R.drawable.em2_07, R.drawable.em2_08, R.drawable.em2_09, R.drawable.em2_10, R.drawable.em2_11, R.drawable.em2_12,
            R.drawable.em2_13, R.drawable.em2_14, R.drawable.em2_15, R.drawable.em2_16, R.drawable.em2_17, R.drawable.em2_18,
            R.drawable.em2_19, R.drawable.em2_20, R.drawable.em2_del
    };

    public static String[] imgNames = new String[]{
            "[em2_01]", "[em2_02]", "[em2_03]", "[em2_04]", "[em2_05]", "[em2_06]", "[em2_07]", "[em2_08]", "[em2_09]", "[em2_10]",
            "[em2_11]", "[em2_12]", "[em2_13]", "[em2_14]", "[em2_15]", "[em2_16]", "[em2_17]", "[em2_18]", "[em2_19]", "[em2_20]",
    };

    private final TextPaint textPaint = new TextPaint();
    private final TextPaint strokePaint = new TextPaint();
    private final Paint debugPaint = new Paint();
    private final Paint borderPaint = new Paint();

    {
        textPaint.setColor(Color.WHITE);
        textPaint.setStyle(Paint.Style.FILL);
        textPaint.setAntiAlias(true);

        strokePaint.setTextSize(textPaint.getTextSize());
        strokePaint.setColor(Color.BLACK);
        strokePaint.setStrokeWidth(3f);
        strokePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        strokePaint.setAntiAlias(true);

        debugPaint.setColor(Color.RED);
        debugPaint.setStyle(Paint.Style.STROKE);
        debugPaint.setAntiAlias(true);
        debugPaint.setStrokeWidth(6f);

        borderPaint.setColor(Color.WHITE);
        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setAntiAlias(true);
        borderPaint.setStrokeWidth(6f);
    }

    @Override
    public void updatePaint(DanmakuItem item, DanmakuDisplayer displayer, DanmakuConfig config) {
        DanmakuItemData danmakuItemData = item.getData();
        // update textPaint
        float textSize = MathUtils.clamp(danmakuItemData.getTextSize(), 12f, 25f) * (displayer.getDensity() - 0.6f);
        textPaint.setColor(danmakuItemData.getTextColor() | Color.argb(255, 0, 0, 0));
        textPaint.setTextSize(textSize * config.getTextSizeScale());
        textPaint.setTypeface(config.getBold() ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
        // update strokePaint
        strokePaint.setTextSize(textPaint.getTextSize());
        strokePaint.setTypeface(textPaint.getTypeface());
        strokePaint.setColor(textPaint.getColor() == DEFAULT_DARK_COLOR ? Color.WHITE : Color.BLACK);
    }

    @Override
    public Size measure(DanmakuItem item, DanmakuDisplayer displayer, DanmakuConfig config) {
        updatePaint(item, displayer, config);
        DanmakuItemData danmakuItemData = item.getData();
        float x = CANVAS_PADDING * 0.5f;

        List<DrawInfo> drawInfos = prepareDrawInfos(textPaint,danmakuItemData.getContent(), x);
        float width = CANVAS_PADDING;
        for (DrawInfo info : drawInfos){
            width+=info.width;
            width+=ELEMENT_SPACE;
        }
        float textWidth = textPaint.measureText(danmakuItemData.getContent());
        float textHeight = getCacheHeight(textPaint);
        return new Size((int) width, (int) (textHeight + CANVAS_PADDING));
    }

    @Override
    public void draw(DanmakuItem item, Canvas canvas, DanmakuDisplayer displayer, DanmakuConfig config) {
        updatePaint(item, displayer, config);
        DanmakuItemData danmakuItemData = item.getData();
        float x = CANVAS_PADDING * 0.5f;
        float y = CANVAS_PADDING * 0.5f - textPaint.ascent();
        // 准备绘制信息
        List<DrawInfo> drawInfos = prepareDrawInfos(textPaint,danmakuItemData.getContent(), x);

        // 根据信息绘制文本和表情
        for (DrawInfo info : drawInfos) {
            if (info.text == null) {
                // 绘制表情图片
                Drawable emoteDrawable = mContext.getResources().getDrawable(info.emoteResId);
                emoteDrawable.setBounds(
                        (int) info.startX,
                        (int) (y - emoteDrawable.getIntrinsicHeight()),
                        (int) (info.startX + info.width),
                        (int) y
                );
                emoteDrawable.draw(canvas);
            } else if (!info.text.isEmpty()) {
                // 绘制文本片段
                canvas.drawText(info.text, info.startX, y, textPaint);
            }
        }

        if (danmakuItemData.getDanmakuStyle() == DanmakuItemData.DANMAKU_STYLE_SELF_SEND) {
            canvas.drawRect(0f, 0f, canvas.getWidth(), canvas.getHeight(), borderPaint);
        }

    }

    private static final int DEFAULT_DARK_COLOR = Color.argb(255, 0x22, 0x22, 0x22);
    private static final int CANVAS_PADDING = 6;
    private static final Map<Float, Float> sTextHeightCache = new HashMap<>();

    private static float getCacheHeight(Paint paint) {
        float textSize = paint.getTextSize();
        Float cachedHeight = sTextHeightCache.get(textSize);
        if (cachedHeight != null) {
            return cachedHeight;
        } else {
            Paint.FontMetrics fontMetrics = paint.getFontMetrics();
            float textHeight = fontMetrics.descent - fontMetrics.ascent + fontMetrics.leading;
            sTextHeightCache.put(textSize, textHeight);
            return textHeight;
        }
    }


    private static class DrawInfo {
        float startX;
        float width;
        int emoteResId;
        String text;
    }

    Pattern pattern = Pattern.compile("(\\[em2_\\d+\\])|(\\[.*?\\](?!\\[em2_\\d+\\]))|([^\\[\\]]+)");

    private List<DrawInfo> prepareDrawInfos(Paint textPaint,String content, float xStart) {
        List<DrawInfo> drawInfos = new ArrayList<>();
        float currentX = xStart;
        Matcher matcher = pattern.matcher(content);

        List<String> parts = new ArrayList<>();
        while (matcher.find()) {
            for (int i = 1; i <= matcher.groupCount(); i++) {
                if (matcher.group(i) != null) {
                    parts.add(matcher.group(i));
                    break;
                }
            }
        }
        int elementSpace = ELEMENT_SPACE;
        for (String part:parts){
            String emotePattern = "\\[em2_\\d+\\]";
            if (part.matches(emotePattern)){
                //是表情
                int emoteIndex = Arrays.asList(imgNames).indexOf(part);
                if (emoteIndex>=0){
                    float emoteWidth = mContext.getResources().getDrawable(imgs[emoteIndex]).getIntrinsicWidth();
                    DrawInfo drawInfo = new DrawInfo();
                    drawInfo.startX = currentX;
                    drawInfo.width = emoteWidth;
                    drawInfo.emoteResId = imgs[emoteIndex];
                    drawInfos.add(drawInfo);
                    currentX += emoteWidth;
                    currentX+=elementSpace;
                }
            }else {
                //是普通文字
                DrawInfo drawInfo = new DrawInfo();
                drawInfo.startX = currentX;
                float textWidth = textPaint.measureText(part);
                drawInfo.width = textWidth;
                drawInfo.text = part;
                drawInfos.add(drawInfo);
                currentX += textWidth;
            }
        }
        return drawInfos;
    }
}
