class Random {
    constructor(seed) {
        seed = BigInt(seed || Date.now()) % BigInt(999999999);
        this.seed = Number(seed.toString());
    }
    next(max) {
        max = max || 10;
        this.seed = (this.seed * 9301 + 49297) % 233280;
        let val = this.seed / 233280.0;
        let num = Math.floor(val * max);
        return num;
    }
    bool() {
        return this.next(100) % 2 == 0;
    }
}

const countInList = (list, item) => { return list.filter((e) => e === item).length; };

function stringToBytes(str) {
    let bytes = [];
    for (let i = 0; i < str.length; ++i) {
        bytes.push(str.charCodeAt(i));
    }
    return bytes;
}

function bytesToHex(byteArr) {
    let num = "0x";
    for (let i = 0; i < byteArr.length; i++) {
        let x = byteArr[i] & 0xff;
        num += x.toString(16);
    }
    return num;
}

function hex2Rgb(hex) {
    hex = hex.replace("#", "");
    if (hex.length == 3) {
        hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
    }
    const bigint = parseInt(hex, 16);
    const r = (bigint >> 16) & 255;
    const g = (bigint >> 8) & 255;
    const b = bigint & 255;
    return { r, g, b };
}

function rgb2Hex(r, g, b) {
    const componentToHex = (c) => c.toString(16).padStart(2,"0");
    return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}

function rgb2Hsv(r, g, b) {
    r /= 255, g /= 255, b /= 255;
    const max = Math.max(r, g, b),
        min = Math.min(r, g, b);
    let h, s, v = max;
    const d = max - min;
    s = max == 0 ? 0 : d / max;
    if (max == min) {
        h = 0;
    } else {
        switch (max) {
            case r:
                h = (g - b) / d + (g < b ? 6 : 0);
                break;
            case g:
                h = (b - r) / d + 2;
                break;
            case b:
                h = (r - g) / d + 4;
                break;
        }
        h /= 6;
    }
    return { h, s, v };
}

function hsv2Rgb(h, s, v) {
    let r, g, b;
    const i = Math.floor(h * 6);
    const f = h * 6 - i;
    const p = v * (1 - s);
    const q = v * (1 - f * s);
    const t = v * (1 - (1 - f) * s);
    switch (i % 6) {
        case 0:
            r = v, g = t, b = p;
            break;
        case 1:
            r = q, g = v, b = p;
            break;
        case 2:
            r = p, g = v, b = t;
            break;
        case 3:
            r = p, g = q, b = v;
            break;
        case 4:
            r = t, g = p, b = v;
            break;
        case 5:
            r = v, g = p, b = q;
            break;
    }
    return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
}

function hex2Hsv(hexcolor) {
    let rgb = hex2Rgb(hexcolor);
    return rgb2Hsv(rgb.r, rgb.g, rgb.b);
}

function hsv2Hex(h, s, v) {
    let rgb = hsv2Rgb(h, s, v);
    return rgb2Hex(rgb.r, rgb.g, rgb.b);
}

function hsvDistance(hsv1, hsv2) {
    let l = Math.sqrt(
        Math.pow(hsv1.h - hsv2.h, 2) +
        Math.pow(hsv1.s - hsv2.s, 2) +
        Math.pow(hsv1.v - hsv2.v, 2)
    );
    l = l > 1 ? 1.0 : l;
    let distance = l / 1.0
    return distance
}

function getSimilarColor(color, colorList) {
    let hsv = hex2Hsv(color);
    let distance = 1;
    let ret = null;
    colorList.forEach((c) => {
        let hsv1 = hex2Hsv(c);
        let d = hsvDistance(hsv, hsv1);
        if (d <= distance) {
            distance = d;
            ret = c;
        }
    });
    if (ret == null) {
        ret = color;
    }
    return ret;
}

function getSvgTextColors(svgText, deduplication = true) {
    let ret = [];
    let colors = [];
    let colors_6 = svgText.match(/#[\da-fA-F]{6}(?=")/g) || [];
    colors.push(...colors_6);
    let colors_3 = svgText.match(/#[\da-fA-F]{3}(?=")/g) || [];
    colors.push(...colors_3);
    if (deduplication && colors != null && colors.length > 0) {
        colors.forEach((c) => {
            if (ret.indexOf(c) < 0) {
                ret.push(c);
            }
        });
    } else {
        ret.push(...colors);
    }
    return ret;
}

function setColorHsvOffset(hexColor, ho = 0, so = 0, vo = 0) {
    let hsv = hex2Hsv(hexColor);
    let h = hsv.h * 360 + ho * 360 % 360;
    h = h % 360;
    h = h < 0 ? h + 360 : h;
    h = h / 360;
    let s = hsv.s + so;
    s = Math.min(Math.max(s, 0), 1);
    let v = hsv.v + vo;
    v = Math.min(Math.max(v, 0), 1);
    let ret = hsv2Hex(h, s, v);
    return ret;
}

function setColorListHsvOffset(hexColors, ho = 0, so = 0, vo = 0) {
    let hexColors_hue = [];
    for (let i in hexColors) {
        c = hexColors[i];
        c1 = setColorHsvOffset(c, ho = ho, so = so, vo = vo);
        hexColors_hue.push(c1);
    }
    return hexColors_hue;
}

function sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)); }

function getSvgShapeItems(parent) {
    return parent.querySelectorAll("path[fill],g[fill],polygon[fill],circle[fill],ellipse[fill]");
}

let animation = false;

async function animationProcess(parent) {
    animation = true;
    let objList = getSvgShapeItems(parent);
    let fillList = [];
    const stroke_color = "#ffffff";
    objList.forEach((item) => {
        item.setAttribute("stroke", stroke_color);
        item.setAttribute("stroke-width", "0.2px");
        fillList.push(item.getAttribute("fill"))
        item.setAttribute("fill", "none");
    });
    await sleep(500);
    async function tween(item, fill) {
        let step = 100;
        for (let i = 0; i < step; i++) {
            let alpha = Math.round((step - (i + 1)) / step * 0xff).toString(16)
            let alphas = alpha.padStart(2, "0");
            let strokecolor = stroke_color + alphas;
            item.setAttribute("stroke", strokecolor);
            item.setAttribute("fill", fill);
            item.setAttribute("opacity", String(i / step));
            await sleep(0.05);
        }
    }
    let t = 10;
    for (let i = 0; i < objList.length; i++) {
        let item = objList[i];
        let fill = fillList[i];
        tween(item, fill);
        await sleep(t);
    }
    animation = false;
}

async function animationHue(svgElement, times = 1) {
    animation = true;
    let svgText = svgElement.innerHTML;
    let t = 0;
    while (animation && (times == 0 || t < times)) {
        for (let a = 1; a <= 360; a += 1) {
            let svgText_a = svgText;
            let colors = getSvgTextColors(svgText_a, true);
            let colors_hue = setColorListHsvOffset(colors, ho = a / 360, so = 0, vo = 0);
            for (let i in colors) {
                svgText_a = svgText_a.replaceAll(colors[i], colors_hue[i]);
            }
            svgElement.innerHTML = svgText_a;
            await sleep(0);
        }
        t++;
    }
    svgElement.innerHTML = svgText;
    animation = false;
}

function hex2Grayscale(hexcolor) {
    let rgb = hex2Rgb(hexcolor);
    return "#" + Math.round((0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b)).toString(16).padStart(2, '0').repeat(3);
}

function colorLevelList(color, s_step = 0.2, v_step = 0.2, s_range = 0.4, v_range = 0.4) {
    let ret = [];
    let hsv = hex2Hsv(color);
    let h = hsv.h;
    let s = hsv.s;
    let v = hsv.v;
    let s_s = s - s_range / 2;
    let s_e = s + s_range / 2;
    let v_s = v - v_range / 2;
    let v_e = v + v_range / 2;
    let color_g = hex2Grayscale(color);
    let g_d = hsvDistance(hsv, hex2Hsv(color_g));
    if (g_d <= 0.1 || (color_g.toLowerCase() == color.toLowerCase()) || (s == 0 && v == 0) || (s == 0 && v == 100)) {
        s_s = s;
        s_e = s;
        v_step = 0.01;
        v_s = v - 0.08;
        v_e = v + 0.08;
    }
    if (s_s < 0) {
        let t = 0 - s_s;
        s_s = 0;
        s_e += t;
    } else if (1 < s_e) {
        let t = s_e - 1;
        s_s -= t;
        s_e = 1;
    }
    if (v_s < 0) {
        let t = 0 - v_s;
        v_s = 0;
        v_e += t;
    } else if (1 < v_e) {
        let t = v_e - 1;
        v_e = 1;
        v_s -= t;
    }
    for (let is = s_s; is <= s_e; is += s_step) {
        for (let iv = v_s; iv <= v_e; iv += v_step) {
            let color = hsv2Hex(h, is, iv);
            if (ret.indexOf(color) < 0) {
                ret.push(color);
            }
        }
    }
    return ret.sort();
}

function colorsExpandLevel(colors, s_step = 0.2, v_step = 0.2, s_range = 0.4, v_range = 0.4) {
    let ret = [];
    colors.forEach((c) => {
        let cList = colorLevelList(c, s_step, v_step, s_range, v_range);
        ret.push(...cList);
    });
    return ret;
}

function svgtextColorsReplacement(svgtext, colors_target, ho = 0, so = 0, vo = 0) {
    if (colors_target == null) {
        colors_target = getSvgTextColors(svgtext, true);
    } else if (!gg) {
        colors_target = colorsExpandLevel(colors_target, s_step = 0.2, v_step = 0.3, s_range = 0.4, v_range = 0.6);
    }
    let colors_source = getSvgTextColors(svgtext, true);
    let colors_r = [];
    colors_source.forEach((c) => {
        let cr = getSimilarColor(c, colors_target);
        colors_r.push(cr);
    });
    let colors_hue = setColorListHsvOffset(colors_r, ho = ho, so = so, vo = vo);
    for (let i in colors_source) {
        svgtext = svgtext.replaceAll(colors_source[i], colors_hue[i]);
    }
    return svgtext;
}

const colorGroups = {
    "c1": ['#ff4400', '#cc9c00', '#990070', '#0e6600', '#002c33'],
    "c2": ['#ff0000', '#ffc000', '#000000', '#9932CC'],
    "c3": ['#b22234', '#3c3b6e', '#ffffff'],
    "c4": ['#bc002d', '#ffffff', '#000000'],
    "c5": ['#0c1c8c', '#ffffff', '#cf142b'],
    "c6": ['#0055a4', '#ffffff', '#ef4135'],
    "c7": ['#028234', '#ffffff', '#de1f24'],
    "c8": ['#ed7137', '#ffffff', '#2e693e', '#060489'],
    "c9": ['#459947', '#fae04b', '#0c2671', '#ffffff'],
    "c10": ['#da3f41', '#fefffd', '#479edb'],
    "c11": ['#f5be55', '#21524f', '#db7b2e', '#81223d'],
    "c12": ['#5CA6CC', '#1ABC9C', '#98FB98', '#800080'],
    "c13": ['#FF0000', '#FFFFFF', '#444444', ],
    "c14": ['#000000', '#fffcff', '#666666'],
    "c15": ['#0000FF', '#008000', '#800080'],
    "c16": ['#0072C6', '#00AEEF', '#6DCFF6', '#BDDDF6', ],
    "pkgd": ['#F2859F', '#FFAFCC', '#FAC0E5', '#D6A2E8', ],
    "obtw": ['#FFA500', '#000080', '#00FFFF', '#FFFFFF', ],
    "gpyf": ['#00FF00', '#800080', '#FFFF00', '#FFFFFF', ],
    "rgwb": ['#FF0000', '#00FF00', '#FFFFFF', '#000000', ],
    "ppgw": ['#4B0082', '#9932CC', '#7CFC00', '#FFFFFF', ],
    "gwgw": ['#708090', '#CFD8DC', '#90A4AE', '#FFFFFF', ],
};

const colorGroups_g = {
    "g1": ['#683d22', '#704523', '#704527', '#7e4e06', '#8b4405', '#985000', '#9c6533', '#a15600', '#a15e18', '#aa5306', '#b25100', '#b9673d', '#bb7300', '#bc6600', '#bf7040', '#c0723a', '#c5733b', '#c97d00', '#ca8700', '#d08122', '#d29038', '#d48114', '#d68f2f', '#e79400', '#eb9c00', '#ecdb8e', '#ed9900', '#f4b54b', '#f4e17f', '#f6eb92', '#f7ad0b', '#fdf2a3', '#ffb040', '#ffc400', '#ffc500', '#ffd147', '#ffd56e', '#ffd926', '#ffdb4f', '#ffdf75', '#ffe176', '#ffe36e', '#ffe74e', '#ffe850', '#fff8ab', ],
    "g2": ['#c07e12', '#ffdb4f', '#b06500', '#ffe850', '#fab044', '#b35b0b', '#c57800', '#ffc200', '#c77a0b', '#a66119', '#f4e17f', '#9a4100', '#ffba00', '#7b4828', '#d68e2f', '#e5b683', '#ddff7e', '#f7d373', '#af6e2a', '#f4a500', '#ffca54', '#e88a00', '#f8b100', '#c17f12', '#ffc100', '#8f3a00', '#ffc500', '#ca8700', '#eb9c00', '#fef7b2', '#fdbf5e', '#9c4f00', '#b16a15', ],
    "g3": ['#c9902d', '#eddb7e', '#9d5b18', '#f3e07e', '#a24d00', '#fcf3a1', '#ffe84d', '#894101', '#d09b4b', '#f0e68a', '#ffdb4f', '#a86000', '#ffbb00', '#e69900', '#eed783', '#a67920', '#ffe100', '#ff892e', '#f7db7c', '#a36526', '#f7b000', '#ba7a11', '#cd9b3a', '#b56f21', '#83543a', '#a45701', '#ffc652', ],
    "g4": ['#ba6c1c', '#ffea84', '#fff98f', '#ffd500', '#a95e00', '#ffc200', '#cc7a00', '#ffc600', '#c56d1d', '#b66600', '#ffe553', '#ffe374', '#81390d', '#ef8c00', '#e38400', '#ffe88f', '#ffdb4f', '#f68c00', '#f48700', '#ffcb51', '#f58700', '#ffe84d', '#9a4901', '#f29000', '#ffd300', '#ffc60a', '#f68900', '#ab5000', '#c37000', '#ffcc00', '#ffbd01', '#b16700', '#f69b00', '#ffd162', '#f49200', ], //'#ffb58a',
    "g5": ['#c9902d', '#eddb7e', '#9d5b18', '#f3e07e', '#a24d00', '#fcf3a1', '#ffe84d', '#894101', '#d09b4b', '#f0e68a', '#ffdb4f', '#a86000', '#ffbb00', '#e69900', '#eed783', '#a67920', '#ffe100', '#ff892e', '#f7db7c', '#a36526', '#f7b000', '#ba7a11', '#cd9b3a', '#b56f21', '#83543a', '#a45701', '#ffc652', ],
    "g6": ['#f5d272', '#9c6225', '#ffde82', '#fec554', '#fdf7c3', '#f7de81', '#af722b', '#ce9f20', '#884806', '#5e3636', '#9e5e17', '#f2d784', '#fcdf75', '#ffe850', '#f9af44', '#a2520a', '#ece084', '#c27b17', '#ffdb4f', '#b77000', '#f2e788', '#9d793d', '#c67e2b', '#e6d87e', '#d6ae26', '#b86900', '#d9a618', '#f0de96', '#9f6013', '#cea54b', ], //,'#b56b6b','#a6fcd9',
    "g7": ['#ffe850', '#a45006', '#dd8f00', '#ffc400', '#b67100', '#b67400', '#fdc400', '#ffc200', '#cf7e0b', '#ffc500', '#d18c00', '#ee9e00', '#fef7b2', '#fec05e', '#ffc100', '#873700', '#ffc60c', '#aa6200', '#cc7c49', '#ffd167', '#f5a600', '#ffca54', '#eb8c00', '#e19c00', '#984d00', '#c26e00', '#c56500', '#f0a800', ],
};


const svg_url = (index) => {
    let svglist = [
        "/content/62c9782036e0d7479ef4766911d311eea537b738cb3b1471f9e7af539bcfd96ei0",
        "/content/0fad1798e1ca341deb749d548ab14f4d0b4fe02a13959467899840d9bd059210i0",
        "/content/29ac03cc1ab54ea487df7f4cb56b8bbec61639a0358e13d65182c9c73002308ci0",
        "/content/d070bb086e9c97c8c22322c001fbd247db6bf388f38e136aa8dd672a2e3c19dei0",
        "/content/349235433e74a87b19a0e7558fd733ba8fcaa480d13ee4586c3eb26e765fea5fi0",
        "/content/ab90fc80531abd2f4ac5f70b4683fd0bfbfa0bcf24f711efd45179b9dfd10b17i0",
        "/content/5e784813f68f8e06cbdf8f41966e02e96e99420f0d11e93d8aed0c53c0b5b77fi0",            
    ];
    if(!window.location.host)
        return "https://ordinals.com"+svglist[index - 1];
    return svglist[index - 1];
};

const getHexSeed = (address) => {
    if (address == null) {
        return Date.now() % 999999999;
    }
    let str = address;
    let bytes = stringToBytes(str);
    let hexseed = bytesToHex(bytes);
    return hexseed;
};

const aen = (a) => {
    try {
        let n = parseInt(a.substring(a.length - 2));
        n = n == 0 ? 1 : n;
        return n || -1;
    } catch (error) {}
    return -1;
};

function loadSvg(url) {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url, false);
    xhr.send(null);
    if (xhr.readyState === 4 && xhr.status === 200) {
        const svgString = xhr.responseXML.documentElement.outerHTML;
        return svgString;
    }
    return null;
}

function colorsRandom(random) {
    let colors_target = [];
    let color_count = 4 + random.next(3);
    if (svg_index == 0 && color_count <= 6)
        color_count += 6;
    let h_list = [];
    for (let i = 0; i < color_count; i++) {
        let h = random.next(12);
        let count = countInList(h_list, h);
        if (count < 1) {
            h_list.push(h);
        } else {
            i--;
        }
    }
    for (let i = 0; i < color_count; i++) {
        let h = h_list[i] * 30;
        h += (random.bool() ? 1 : -1) * random.next(16);
        h = h < 0 ? h + 360 : h;
        h = h % 360 / 360;
        let s = 1 - (random.bool() ? i / color_count : 0.05);
        let v = 1 - (random.bool() ? i / color_count / 2 : 0.05);
        if (random.bool() && i == color_count - 1) {
            s = (2 + random.next(4)) * 0.05; //0.1;
            v = 1;
        } else if (random.bool() && i == color_count - 2) {
            s = (1 + random.next(6)) * 0.05; //0.2;
            v = 0.1;
        }
        let hex = hsv2Hex(h, s, v);
        colors_target.push(hex);
    }
    return colors_target;
}

function colorsRandomGroup(random) {
    let gp = gg ? colorGroups_g : colorGroups;
    let keys = Object.keys(gp);
    let key = gg ? `g${svg_index}` : keys[random.next(keys.length)];
    let colors_target = gp[key];
    return colors_target;
}

function assignColors(svgtext, random) {
    let ret = svgtext;
    let colors_target = null;
    let m_count = Object.keys(colorGroups).length;
    let rc = random.next(100);
    let needhsv = true;
    let sc = 7;
    if (gg) {
        colors_target = colorsRandomGroup(random);
        needhsv = false;
    } else if (rc < sc) {
        ret = svgtext;
        needhsv = false;
    } else if (sc <= rc && rc < m_count + sc && svg_index > 0) {
        colors_target = colorsRandomGroup(random);
    } else {
        colors_target = colorsRandom(random)
    }
    let ho = 0;
    let so = 0;
    let vo = 0;
    if (needhsv) {
        ho = random.next(10) * 36 / 360;
        so = 0;
        vo = random.next(15) / 100;
    }
    ret = svgtextColorsReplacement(svgtext, colors_target, ho, so, vo);
    return ret;
}

function makeSvgBg(random) {
    let ho = random.next(12) * 30 / 360;
    let c1 = setColorHsvOffset("#434fbb", ho = ho, so = 0, v0 = 0);
    let c2 = setColorHsvOffset("#0d0f2f", ho = ho, so = 0, v0 = 0);
    if (gg) {
        c1 = "#8a2d2d";
        c2 = "#210404";
    }
    let o1 = "0";
    let o2 = "1";
    let svgtext_bg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100" xml:space="preserve"><radialGradient id="bgcl" cx="50" cy="50" r="50" gradientUnits="userSpaceOnUse"><stop offset="${o1}" stop-color="${c1}"/><stop offset="${o2}" stop-color="${c2}"/></radialGradient><path style="fill:url(#bgcl)" d="M0 0h100v100H0z"/></svg>`;
    return svgtext_bg;
}

let svg_index = 0;
let svgtext_source = null;
let svgtext_color = null;
let svgtext_bg = null;
let gg = false;

async function start() {
    let body = document.body;
    while (body == null) {
        await sleep(1);
        body = document.body;
    }
    body.style.margin = "0px";
    body.style.background = "black";
    let bgparent = document.createElement('div');
    bgparent.class = "bg";
    bgparent.style.cssText = "position: fixed; width: 100%; height: 100%; display: flex; justify-content: center;";
    body.appendChild(bgparent);
    let svgparent = document.createElement('div');
    svgparent.class = "wrapper";
    svgparent.style.cssText = "position: fixed; width: 100%; height: 100%; display: flex; justify-content: center;";
    body.appendChild(svgparent);
    let baseData = p || {};
    let random = new Random(getHexSeed(baseData.address));
    svg_index = baseData ?.mask || (random.next(7) + 1);
    let _aen=aen(baseData.address);
    gg = _aen%svg_index == Math.abs(_aen-svg_index);
    if (svgtext_source == null) {
        svgtext_source = loadSvg(svg_url(svg_index));
        let ss = svgtext_source.replace(new RegExp('<radialGradient id="bgcl"[^>]*>[\\s\\S]*?</radialGradient><path[\\s\\S]*?/>', 'g'), "");
        ss = ss.replaceAll('<path stroke="#fff" stroke-width="0.2px" ', "<path ");
        ss = ss.replaceAll(/(#[\da-fA-F]{6})00/g, "$1");
        svgtext_source = ss;
    }
    if (svgtext_source == null) {
        return;
    }
    svgtext_bg = makeSvgBg(random);
    bgparent.innerHTML = svgtext_bg;
    svgtext_color = assignColors(svgtext_source, random);
    window.SvgDataMask = {
        "svgtext_source": svgtext_source,
        "svgtext_color": svgtext_color,
        "svgtext_bg": svgtext_bg,
    };
    svgparent.innerHTML = svgtext_color;
    if (baseData.animation != false) {
        await animationProcess(svgparent);
        svgparent.onclick = () => {
            if (!animation) {
                animationHue(svgparent);
            }
        };
    }
}

start();