package com.ruoyi.common.dev;

import java.util.Objects;

// Unix \033[字背景颜色;字体颜色m字符串\033[0m
// 高亮+闪烁+红色前景+蓝色背景
// 32位 |设置8位 0 0 0 0 0 启用背景色 背景高亮 字体高亮|字体风格8位|字体色8位|背景色8位
public class Konsole {
    private static final String RESET = "\033[0m";  // Text Reset
    private static final int COLOR_OFFSET = 8;
    private static final int COLOR_MASK = 0xFF00;
    private static final int BG_COLOR_OFFSET = 0;
    private static final int BG_COLOR_MASK = 0xFF;
    private static final int FONT_STYLE_OFFSET = 16;
    private static final int FONT_STYLE_MASK = 0xFF0000;
    private static final int STYLE_OFFSET = 24;
    private static final int STYLE_MASK = 0x7F000000;

    // 1. 原始值: 需要SetXXX(值)设置, MakeStyle
    public static final int FONT_BRIGHT = 1;
    public static final int BG_BRIGHT = 1 << 1;
    public static final int BG_ENABLED = 1 << 2;

    public static final int NORMAL = 0; // 3:斜体 4:下划线 5:闪烁 6:默认 7:白底 8:透明 9:删除线
    public static final int BOLD = 1;
    public static final int FAINT = 2;
    public static final int ITALIC = 3;
    public static final int UNDERLINE = 4;
    public static final int FLASH = 5;
    public static final int DEFAULT = 6;
    public static final int WHITE_BACKGROUND = 7;
    public static final int TRANSLUCENT = 8;
    public static final int STRIKETHROUGH = 9;
    public static final int DOUBLE_UNDER_LINE = 21;

    public static final int BLACK = 30;   // BLACK
    public static final int RED = 31;     // RED
    public static final int GREEN = 32;   // GREEN
    public static final int YELLOW = 33;  // YELLOW
    public static final int BLUE = 34;    // BLUE
    public static final int PURPLE = 35;  // PURPLE
    public static final int CYAN = 36;    // CYAN
    public static final int WHITE = 37;   // WHITE

    // 2. 预置值: 可以 | 或拼接
    public static final int S_FONT_BRIGHT = FONT_BRIGHT << STYLE_OFFSET;
    public static final int S_BG_BRIGHT = BG_BRIGHT << STYLE_OFFSET;
    public static final int S_BG_ENABLED = BG_BRIGHT << STYLE_OFFSET;

    public static final int FS_NORMAL = NORMAL;
    public static final int FS_BOLD = BOLD << FONT_STYLE_OFFSET;
    public static final int FS_FAINT = FAINT << FONT_STYLE_OFFSET;
    public static final int FS_ITALIC = ITALIC << FONT_STYLE_OFFSET;
    public static final int FS_UNDERLINE = UNDERLINE << FONT_STYLE_OFFSET;
    public static final int FS_FLASH = FLASH << FONT_STYLE_OFFSET;
    public static final int FS_DEFAULT = DEFAULT << FONT_STYLE_OFFSET;
    public static final int FS_WHITE_BACKGROUND = WHITE_BACKGROUND << FONT_STYLE_OFFSET;
    public static final int FS_TRANSLUCENT = TRANSLUCENT << FONT_STYLE_OFFSET;
    public static final int FS_STRIKETHROUGH = STRIKETHROUGH << FONT_STYLE_OFFSET;
    public static final int FS_DOUBLE_UNDER_LINE = DOUBLE_UNDER_LINE << STYLE_OFFSET;

    public static final int FC_BLACK = BLACK << COLOR_OFFSET;
    public static final int FC_RED = RED << COLOR_OFFSET;
    public static final int FC_GREEN = GREEN << COLOR_OFFSET;
    public static final int FC_YELLOW = YELLOW << COLOR_OFFSET;
    public static final int FC_BLUE = BLUE << COLOR_OFFSET;
    public static final int FC_PURPLE = PURPLE << COLOR_OFFSET;
    public static final int FC_CYAN = CYAN << COLOR_OFFSET;
    public static final int FC_WHITE = WHITE << COLOR_OFFSET;

    public static final int BC_BLACK = BLACK;
    public static final int BC_RED = RED;
    public static final int BC_GREEN = GREEN;
    public static final int BC_YELLOW = YELLOW;
    public static final int BC_BLUE = BLUE;
    public static final int BC_PURPLE = PURPLE;
    public static final int BC_CYAN = CYAN;
    public static final int BC_WHITE = WHITE;

    public static final int FC_BRIGHT_BLACK = (BLACK + 60) << COLOR_OFFSET;
    public static final int FC_BRIGHT_RED = (RED + 60) << COLOR_OFFSET;
    public static final int FC_BRIGHT_GREEN = (GREEN + 60) << COLOR_OFFSET;
    public static final int FC_BRIGHT_YELLOW = (YELLOW + 60) << COLOR_OFFSET;
    public static final int FC_BRIGHT_BLUE = (BLUE + 60) << COLOR_OFFSET;
    public static final int FC_BRIGHT_PURPLE = (PURPLE + 60) << COLOR_OFFSET;
    public static final int FC_BRIGHT_CYAN = (CYAN + 60) << COLOR_OFFSET;
    public static final int FC_BRIGHT_WHITE = (WHITE + 60) << COLOR_OFFSET;

    public static final int BC_BRIGHT_BLACK = BLACK + 70;
    public static final int BC_BRIGHT_RED = RED + 70;
    public static final int BC_BRIGHT_GREEN = GREEN + 70;
    public static final int BC_BRIGHT_YELLOW = YELLOW + 70;
    public static final int BC_BRIGHT_BLUE = BLUE + 70;
    public static final int BC_BRIGHT_PURPLE = PURPLE + 70;
    public static final int BC_BRIGHT_CYAN = CYAN + 70;
    public static final int BC_BRIGHT_WHITE = WHITE + 70;

    public int style;

    public Konsole(int style) {
        this.style = style;
    }

    public Konsole SetFontColor(int color) {
        this.style = SetAttribute(color, COLOR_OFFSET, COLOR_MASK);
        return this;
    }

    public Konsole SetFontStyle(int style) {
        this.style = SetAttribute(style, FONT_STYLE_OFFSET, FONT_STYLE_MASK);
        return this;
    }

    public Konsole SetBGColor(int color) {
        this.style = SetAttribute(color, BG_COLOR_OFFSET, BG_COLOR_MASK);
        return this;
    }

    public Konsole SetStyleConfig(int style, boolean enabled) {
        if(enabled)
            this.style = style << STYLE_OFFSET | (this.style & ~STYLE_MASK);
        else
            this.style = (this.style & ~STYLE_MASK) & ~(style << STYLE_OFFSET);
        return this;
    }

    public int Style() {
        return style;
    }

    public Konsole Style(int style) {
        this.style = style;
        return this;
    }

    private int SetAttribute(int color, int offset, int mask) {
        int newColor = color << offset;
        return (this.style & ~mask) | newColor;
    }

    private static int GetAttribute(int style, int offset, int mask) {
        return (style & mask) >> offset;
    }

    @Override
    public String toString() {
        return GetEscString(this.style);
    }

    public String Output(String str)
    {
        StringBuilder sb = new StringBuilder();
        sb.append(GetEscString(style));
        sb.append(str);
        sb.append(RESET);
        return sb.toString();
    }

    public static String MakeText(String str, int style)
    {
        StringBuilder sb = new StringBuilder();
        sb.append(GetEscString(style));
        sb.append(str);
        sb.append(RESET);
        return sb.toString();
    }

    public static int MakeStyle(int fontColor, int fontStyle, int bgColor, int style)
    {
        return (fontColor << COLOR_OFFSET) | (fontStyle << FONT_STYLE_OFFSET) | (bgColor << BG_COLOR_OFFSET) << (style << STYLE_OFFSET);
    }

    public static int GenStyle(int... mask)
    {
        int style = 0;
        for (int j : mask) style |= j;
        return style;
    }

    private static String GetEscString(int style) {
        if (style == 0) return RESET;
        StringBuilder sb = new StringBuilder();
        sb.append("\033[");
        sb.append(GenStyleStr(style));
        sb.append("m");
        return sb.toString();
    }

    private static String GenStyleStr(int style) {
        int enableBG = GetAttribute(style, 2, STYLE_MASK);
        int fontColor = GetAttribute(style, COLOR_OFFSET, COLOR_MASK);
        int fontStyle = GetAttribute(style, FONT_STYLE_OFFSET, FONT_STYLE_MASK);

        StringBuilder sb = new StringBuilder();
        if(fontStyle != 0)
            sb.append(fontStyle).append(";");
        if(fontColor != 0)
        {
            int hlFont = GetAttribute(style, 0, STYLE_MASK);
            fontColor = GenColor(fontColor, hlFont != 0 ? 90 - 30 : 0);
            sb.append(fontColor).append(";");
        }
        if(enableBG != 0)
        {
            int bgColor = GetAttribute(style, BG_COLOR_OFFSET, BG_COLOR_MASK);
            if(bgColor != 0)
            {
                int hlBG = GetAttribute(style, 1, STYLE_MASK);
                bgColor = GenColor(bgColor, hlBG != 0 ? 100 - 30 : 40 - 30);
                sb.append(bgColor).append(";");
            }
        }

        if(sb.lastIndexOf(";") == sb.length() - 1)
            sb.deleteCharAt(sb.length() - 1);

        return sb.toString();
    }

    private static int GenColor(int color, int base)
    {
        return color + base;
    }

    public static final int STDOUT = 1;
    public static final int STDERR = 2;
    public static class out
    {
        public static void println(int style, Object obj)
        {
            System.out.println(MakeText(Objects.toString(obj), style));
        }

        public static void print(int style, Object obj)
        {
            System.out.print(MakeText(Objects.toString(obj), style));
        }

        public static void printf(int style, String fmt, Object...args)
        {
            if(null == fmt)
                println(style, fmt);
            else
                println(style, String.format(fmt, args));
        }
    }

    public static class err
    {
        public static void println(int style, Object obj)
        {
            System.err.println(MakeText(Objects.toString(obj), style));
        }

        public static void print(int style, Object obj)
        {
            System.err.print(MakeText(Objects.toString(obj), style));
        }

        public static void printf(int style, String fmt, Object...args)
        {
            if(null == fmt)
                println(style, fmt);
            else
                println(style, String.format(fmt, args));
        }
    }

    public static void cout(int style, Object obj)
    {
        out.println(style, obj);
    }

    public static void cerr(int style, Object obj)
    {
        err.println(style, obj);
    }

    public static void printf(int style, String fmt, Object...args)
    {
        out.printf(style, fmt, args);
    }

    public static void fprintf(int file, int style, String fmt, Object...args)
    {
        if(file == STDERR)
            err.printf(style, fmt, args);
        else
            out.printf(style, fmt, args);
    }

    public static String sprintf(int style, String fmt, Object...args)
    {
        return MakeText(null != fmt ? String.format(fmt, args) : "null", style);
    }

    public static void main(String[] args) {
        System.out.println("\033[0;7;31;44m TEXT \033[0m");
        System.out.println(MakeText("TEXT", FS_UNDERLINE | FC_BLUE | S_BG_BRIGHT | S_BG_ENABLED | BC_CYAN | S_FONT_BRIGHT));
    }
}
