<header>RGB</header>

<body>
    <script>
        class RGB {
            #r = 0
            #g = 0
            #b = 0
            onError(message){
                //throw new Error(message);
                console.log(`ERROR: ${message}`);
            }
            checkChannelValue(val) {
                val = +val
                if (typeof val !== "number" || val < 0 || val > 255) {
                    this.onError(`invalid channel value: ${val}`)
                }
            }
            toHex(val){
                    return val.toString(16).padStart(2, '0').toUpperCase();
            }
            get r() {
                return this.#r;
            }
            set r(val) {
                this.checkChannelValue(val);
                this.#r = +val;
            }
            get g() {
                return this.#g;
            }
            set g(val) {
                this.checkChannelValue(val);
                this.#g = +val;
            }
            get b() {
                return this.#b;
            }
            set b(val) {
                this.checkChannelValue(val);
                this.#b = +val;
            }
            set hex(val) {
                let matchColors = /^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/;
                let match = matchColors.exec(val);
                if (match !== null && match.length == 4) {
                    this.r = parseInt(`${match[1]}`, 16);
                    this.g = parseInt(`${match[2]}`, 16);
                    this.b = parseInt(`${match[3]}`, 16);
                    return;
                }
                this.onError(`incorrect hex color parameter: ${val}`);
            }
            get hex() {
                return `#${this.toHex(this.r)}${this.toHex(this.g)}${this.toHex(this.b)}`;
            }
            set rgb(val) {
                let matchColors = /^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/;
                let match = matchColors.exec(val);
                if (match !== null && match.length == 4) {
                    this.r = match[1];
                    this.g = match[2];
                    this.b = match[3];
                    return;
                }
                this.onError(`incorrect rgb color parameter: ${val}`);
            }
            get rgb() {
                return `rgb(${this.r}, ${this.g}, ${this.b})`;
            }

          
            constructor(colorString) {
                if (colorString) {
                    if (colorString.startsWith(`#`))
                        this.hex = colorString;
                    else
                        this.rgb = colorString;
                }
            }

        }
        function assertAreEqual(actual, expected) {
            if (actual != expected)
                throw new Error(`not expected value. actual: ${actual}, expected: ${expected}`);
        }
        let color = new RGB('#AABBFF');
        assertAreEqual(color.hex, '#AABBFF');
        color = new RGB('rgb(55, 49, 121)');
        assertAreEqual(color.rgb, `rgb(55, 49, 121)`);
        assertAreEqual(color.hex, `#373179`);
        color.rgb = `rgb(55, 49, 121)`;
        assertAreEqual(color.r, 55);
        assertAreEqual(color.g, 49);
        assertAreEqual(color.b, 121);
        assertAreEqual(color.rgb, `rgb(55, 49, 121)`);
        assertAreEqual(color.hex, `#373179`);
        const rgb = new RGB()
        rgb.r = 15
        rgb.g = 128
        rgb.b = 192
        console.log(rgb.hex) //#0F80C0
        console.log(rgb.rgb) //rgb(15,128,192)
        rgb.hex = '#203040'
        console.log(rgb.rgb) //rgb(32, 48, 64)
        rgb.rgb = 'rgb(100, 90, 50)'
        console.log(rgb.r, rgb.g, rgb.b) //100, 90, 50

        rgb.r = 1000   //RangeError
        rgb.hex = 'дичь' //SyntaxError
    </script>
</body>