/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * ---------------------------------------------------------------------
 *
 * Portions of this file were modified and ported to Vala by Victor Vintorez in 2026.
 * These modifications are licensed under the European Union Public License (EUPL),
 * Version 1.2 or later. You may obtain a copy of the License at:
 * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
 */

using GLib;

namespace MaterialColorUtilities {
	/**
	 * Represents a Material color scheme, a mapping of color roles to colors.
	 *
	 * @deprecated Please use dynamiccolor.DynamicScheme instead. Refer
	 *     to https://github.com/material-foundation/material-color-utilities/blob/main/make_schemes.md
	 *     for migration guidance.
	 */
	public class Scheme : Object {
		public int primary { get; set; }
		public int on_primary { get; set; }
		public int primary_container { get; set; }
		public int on_primary_container { get; set; }
		public int secondary { get; set; }
		public int on_secondary { get; set; }
		public int secondary_container { get; set; }
		public int on_secondary_container { get; set; }
		public int tertiary { get; set; }
		public int on_tertiary { get; set; }
		public int tertiary_container { get; set; }
		public int on_tertiary_container { get; set; }
		public int error { get; set; }
		public int on_error { get; set; }
		public int error_container { get; set; }
		public int on_error_container { get; set; }
		public int background { get; set; }
		public int on_background { get; set; }
		public int surface { get; set; }
		public int on_surface { get; set; }
		public int surface_variant { get; set; }
		public int on_surface_variant { get; set; }
		public int outline { get; set; }
		public int outline_variant { get; set; }
		public int shadow { get; set; }
		public int scrim { get; set; }
		public int inverse_surface { get; set; }
		public int inverse_on_surface { get; set; }
		public int inverse_primary { get; set; }

		public Scheme(int primary = 0,
			int on_primary = 0,
			int primary_container = 0,
			int on_primary_container = 0,
			int secondary = 0,
			int on_secondary = 0,
			int secondary_container = 0,
			int on_secondary_container = 0,
			int tertiary = 0,
			int on_tertiary = 0,
			int tertiary_container = 0,
			int on_tertiary_container = 0,
			int error = 0,
			int on_error = 0,
			int error_container = 0,
			int on_error_container = 0,
			int background = 0,
			int on_background = 0,
			int surface = 0,
			int on_surface = 0,
			int surface_variant = 0,
			int on_surface_variant = 0,
			int outline = 0,
			int outline_variant = 0,
			int shadow = 0,
			int scrim = 0,
			int inverse_surface = 0,
			int inverse_on_surface = 0,
			int inverse_primary = 0) {
			this.primary = primary;
			this.on_primary = on_primary;
			this.primary_container = primary_container;
			this.on_primary_container = on_primary_container;
			this.secondary = secondary;
			this.on_secondary = on_secondary;
			this.secondary_container = secondary_container;
			this.on_secondary_container = on_secondary_container;
			this.tertiary = tertiary;
			this.on_tertiary = on_tertiary;
			this.tertiary_container = tertiary_container;
			this.on_tertiary_container = on_tertiary_container;
			this.error = error;
			this.on_error = on_error;
			this.error_container = error_container;
			this.on_error_container = on_error_container;
			this.background = background;
			this.on_background = on_background;
			this.surface = surface;
			this.on_surface = on_surface;
			this.surface_variant = surface_variant;
			this.on_surface_variant = on_surface_variant;
			this.outline = outline;
			this.outline_variant = outline_variant;
			this.shadow = shadow;
			this.scrim = scrim;
			this.inverse_surface = inverse_surface;
			this.inverse_on_surface = inverse_on_surface;
			this.inverse_primary = inverse_primary;
		}

		/** Creates a light theme Scheme from a source color in ARGB, i.e. a hex code. */
		public static Scheme light(int argb) {
			return light_from_core_palette(CorePalette.of(argb));
		}

		/** Creates a dark theme Scheme from a source color in ARGB, i.e. a hex code. */
		public static Scheme dark(int argb) {
			return dark_from_core_palette(CorePalette.of(argb));
		}

		/** Creates a light theme content-based Scheme from a source color in ARGB, i.e. a hex code. */
		public static Scheme light_content(int argb) {
			return light_from_core_palette(CorePalette.content_of(argb));
		}

		/** Creates a dark theme content-based Scheme from a source color in ARGB, i.e. a hex code. */
		public static Scheme dark_content(int argb) {
			return dark_from_core_palette(CorePalette.content_of(argb));
		}

		private static Scheme light_from_core_palette(CorePalette core) {
			return new Scheme()
			        .with_primary(core.a1.tone(40))
			        .with_on_primary(core.a1.tone(100))
			        .with_primary_container(core.a1.tone(90))
			        .with_on_primary_container(core.a1.tone(10))
			        .with_secondary(core.a2.tone(40))
			        .with_on_secondary(core.a2.tone(100))
			        .with_secondary_container(core.a2.tone(90))
			        .with_on_secondary_container(core.a2.tone(10))
			        .with_tertiary(core.a3.tone(40))
			        .with_on_tertiary(core.a3.tone(100))
			        .with_tertiary_container(core.a3.tone(90))
			        .with_on_tertiary_container(core.a3.tone(10))
			        .with_error(core.error.tone(40))
			        .with_on_error(core.error.tone(100))
			        .with_error_container(core.error.tone(90))
			        .with_on_error_container(core.error.tone(10))
			        .with_background(core.n1.tone(99))
			        .with_on_background(core.n1.tone(10))
			        .with_surface(core.n1.tone(99))
			        .with_on_surface(core.n1.tone(10))
			        .with_surface_variant(core.n2.tone(90))
			        .with_on_surface_variant(core.n2.tone(30))
			        .with_outline(core.n2.tone(50))
			        .with_outline_variant(core.n2.tone(80))
			        .with_shadow(core.n1.tone(0))
			        .with_scrim(core.n1.tone(0))
			        .with_inverse_surface(core.n1.tone(20))
			        .with_inverse_on_surface(core.n1.tone(95))
			        .with_inverse_primary(core.a1.tone(80));
		}

		private static Scheme dark_from_core_palette(CorePalette core) {
			return new Scheme()
			        .with_primary(core.a1.tone(80))
			        .with_on_primary(core.a1.tone(20))
			        .with_primary_container(core.a1.tone(30))
			        .with_on_primary_container(core.a1.tone(90))
			        .with_secondary(core.a2.tone(80))
			        .with_on_secondary(core.a2.tone(20))
			        .with_secondary_container(core.a2.tone(30))
			        .with_on_secondary_container(core.a2.tone(90))
			        .with_tertiary(core.a3.tone(80))
			        .with_on_tertiary(core.a3.tone(20))
			        .with_tertiary_container(core.a3.tone(30))
			        .with_on_tertiary_container(core.a3.tone(90))
			        .with_error(core.error.tone(80))
			        .with_on_error(core.error.tone(20))
			        .with_error_container(core.error.tone(30))
			        .with_on_error_container(core.error.tone(90))
			        .with_background(core.n1.tone(10))
			        .with_on_background(core.n1.tone(90))
			        .with_surface(core.n1.tone(10))
			        .with_on_surface(core.n1.tone(90))
			        .with_surface_variant(core.n2.tone(30))
			        .with_on_surface_variant(core.n2.tone(80))
			        .with_outline(core.n2.tone(60))
			        .with_outline_variant(core.n2.tone(30))
			        .with_shadow(core.n1.tone(0))
			        .with_scrim(core.n1.tone(0))
			        .with_inverse_surface(core.n1.tone(90))
			        .with_inverse_on_surface(core.n1.tone(20))
			        .with_inverse_primary(core.a1.tone(40));
		}

		public Scheme with_primary(int primary) {
			this.primary = primary;
			return this;
		}

		public Scheme with_on_primary(int on_primary) {
			this.on_primary = on_primary;
			return this;
		}

		public Scheme with_primary_container(int primary_container) {
			this.primary_container = primary_container;
			return this;
		}

		public Scheme with_on_primary_container(int on_primary_container) {
			this.on_primary_container = on_primary_container;
			return this;
		}

		public Scheme with_secondary(int secondary) {
			this.secondary = secondary;
			return this;
		}

		public Scheme with_on_secondary(int on_secondary) {
			this.on_secondary = on_secondary;
			return this;
		}

		public Scheme with_secondary_container(int secondary_container) {
			this.secondary_container = secondary_container;
			return this;
		}

		public Scheme with_on_secondary_container(int on_secondary_container) {
			this.on_secondary_container = on_secondary_container;
			return this;
		}

		public Scheme with_tertiary(int tertiary) {
			this.tertiary = tertiary;
			return this;
		}

		public Scheme with_on_tertiary(int on_tertiary) {
			this.on_tertiary = on_tertiary;
			return this;
		}

		public Scheme with_tertiary_container(int tertiary_container) {
			this.tertiary_container = tertiary_container;
			return this;
		}

		public Scheme with_on_tertiary_container(int on_tertiary_container) {
			this.on_tertiary_container = on_tertiary_container;
			return this;
		}

		public Scheme with_error(int error) {
			this.error = error;
			return this;
		}

		public Scheme with_on_error(int on_error) {
			this.on_error = on_error;
			return this;
		}

		public Scheme with_error_container(int error_container) {
			this.error_container = error_container;
			return this;
		}

		public Scheme with_on_error_container(int on_error_container) {
			this.on_error_container = on_error_container;
			return this;
		}

		public Scheme with_background(int background) {
			this.background = background;
			return this;
		}

		public Scheme with_on_background(int on_background) {
			this.on_background = on_background;
			return this;
		}

		public Scheme with_surface(int surface) {
			this.surface = surface;
			return this;
		}

		public Scheme with_on_surface(int on_surface) {
			this.on_surface = on_surface;
			return this;
		}

		public Scheme with_surface_variant(int surface_variant) {
			this.surface_variant = surface_variant;
			return this;
		}

		public Scheme with_on_surface_variant(int on_surface_variant) {
			this.on_surface_variant = on_surface_variant;
			return this;
		}

		public Scheme with_outline(int outline) {
			this.outline = outline;
			return this;
		}

		public Scheme with_outline_variant(int outline_variant) {
			this.outline_variant = outline_variant;
			return this;
		}

		public Scheme with_shadow(int shadow) {
			this.shadow = shadow;
			return this;
		}

		public Scheme with_scrim(int scrim) {
			this.scrim = scrim;
			return this;
		}

		public Scheme with_inverse_surface(int inverse_surface) {
			this.inverse_surface = inverse_surface;
			return this;
		}

		public Scheme with_inverse_on_surface(int inverse_on_surface) {
			this.inverse_on_surface = inverse_on_surface;
			return this;
		}

		public Scheme with_inverse_primary(int inverse_primary) {
			this.inverse_primary = inverse_primary;
			return this;
		}

		public string format() {
			return new StringBuilder()
			        .append("Scheme{")
			        .append("primary=%d, ".printf(primary))
			        .append("on_primary=%d, ".printf(on_primary))
			        .append("primary_container=%d, ".printf(primary_container))
			        .append("on_primary_container=%d, ".printf(on_primary_container))
			        .append("secondary=%d, ".printf(secondary))
			        .append("on_secondary=%d, ".printf(on_secondary))
			        .append("secondary_container=%d, ".printf(secondary_container))
			        .append("on_secondary_container=%d, ".printf(on_secondary_container))
			        .append("tertiary=%d, ".printf(tertiary))
			        .append("on_tertiary=%d, ".printf(on_tertiary))
			        .append("tertiary_container=%d, ".printf(tertiary_container))
			        .append("on_tertiary_container=%d, ".printf(on_tertiary_container))
			        .append("error=%d, ".printf(error))
			        .append("on_error=%d, ".printf(on_error))
			        .append("error_container=%d, ".printf(error_container))
			        .append("on_error_container=%d, ".printf(on_error_container))
			        .append("background=%d, ".printf(background))
			        .append("on_background=%d, ".printf(on_background))
			        .append("surface=%d, ".printf(surface))
			        .append("on_surface=%d, ".printf(on_surface))
			        .append("surface_variant=%d, ".printf(surface_variant))
			        .append("on_surface_variant=%d, ".printf(on_surface_variant))
			        .append("outline=%d, ".printf(outline))
			        .append("outline_variant=%d, ".printf(outline_variant))
			        .append("shadow=%d, ".printf(shadow))
			        .append("scrim=%d, ".printf(scrim))
			        .append("inverse_surface=%d, ".printf(inverse_surface))
			        .append("inverse_on_surface=%d, ".printf(inverse_on_surface))
			        .append("inverse_primary=%d}".printf(inverse_primary))
			        .str;
		}

		public bool equals(Object? object) {
			if (this == object) {
				return true;
			}

			if (!(object is Scheme)) {
				return false;
			}

			Scheme other = (Scheme) object;

			if (this.primary != other.on_primary) {
				return false;
			}

			if (this.on_primary != other.on_primary) {
				return false;
			}

			if (this.primary_container != other.primary_container) {
				return false;
			}

			if (this.on_primary_container != other.on_primary_container) {
				return false;
			}

			if (this.secondary != other.secondary) {
				return false;
			}

			if (this.on_secondary != other.on_secondary) {
				return false;
			}

			if (this.secondary_container != other.secondary_container) {
				return false;
			}

			if (this.on_secondary_container != other.on_secondary_container) {
				return false;
			}

			if (this.tertiary != other.tertiary) {
				return false;
			}

			if (this.on_tertiary != other.on_tertiary) {
				return false;
			}

			if (this.tertiary_container != other.tertiary_container) {
				return false;
			}

			if (this.on_tertiary_container != other.on_tertiary_container) {
				return false;
			}

			if (this.error != other.error) {
				return false;
			}

			if (this.on_error != other.on_error) {
				return false;
			}

			if (this.error_container != other.error_container) {
				return false;
			}

			if (this.on_error_container != other.on_error_container) {
				return false;
			}

			if (this.background != other.background) {
				return false;
			}

			if (this.on_background != other.on_background) {
				return false;
			}

			if (this.surface != other.surface) {
				return false;
			}

			if (this.on_surface != other.on_surface) {
				return false;
			}

			if (this.surface_variant != other.surface_variant) {
				return false;
			}

			if (this.on_surface_variant != other.on_surface_variant) {
				return false;
			}

			if (this.outline != other.outline) {
				return false;
			}

			if (this.outline_variant != other.outline_variant) {
				return false;
			}

			if (this.shadow != other.shadow) {
				return false;
			}

			if (this.scrim != other.scrim) {
				return false;
			}

			if (this.inverse_surface != other.inverse_surface) {
				return false;
			}

			if (this.inverse_on_surface != other.inverse_on_surface) {
				return false;
			}

			if (this.inverse_primary != other.inverse_primary) {
				return false;
			}

			return true;
		}

		public int hash_code() {
			int result = (int) direct_hash(this);

			result = 31 * result + this.primary;
			result = 31 * result + this.on_primary;
			result = 31 * result + this.primary_container;
			result = 31 * result + this.on_primary_container;
			result = 31 * result + this.secondary;
			result = 31 * result + this.on_secondary;
			result = 31 * result + this.secondary_container;
			result = 31 * result + this.on_secondary_container;
			result = 31 * result + this.tertiary;
			result = 31 * result + this.on_tertiary;
			result = 31 * result + this.tertiary_container;
			result = 31 * result + this.on_tertiary_container;
			result = 31 * result + this.error;
			result = 31 * result + this.on_error;
			result = 31 * result + this.error_container;
			result = 31 * result + this.on_error_container;
			result = 31 * result + this.background;
			result = 31 * result + this.on_background;
			result = 31 * result + this.surface;
			result = 31 * result + this.on_surface;
			result = 31 * result + this.surface_variant;
			result = 31 * result + this.on_surface_variant;
			result = 31 * result + this.outline;
			result = 31 * result + this.outline_variant;
			result = 31 * result + this.shadow;
			result = 31 * result + this.scrim;
			result = 31 * result + this.inverse_surface;
			result = 31 * result + this.inverse_on_surface;
			result = 31 * result + this.inverse_primary;

			return result;
		}
	}
}
