import "@polymer/iron-collapse/iron-collapse.js";
import "@polymer/iron-flex-layout/iron-flex-layout.js";
import "@polymer/iron-localstorage/iron-localstorage.js";
import "@polymer/paper-styles/element-styles/paper-material-styles.js";
import "@polymer/paper-styles/typography.js";

import { initialize } from "@open-iframe-resizer/core";
import * as Polymer from "@polymer/polymer";
import { afterNextRender } from "@polymer/polymer/lib/utils/render-status.js";

const HEX_PARSE_SHORTHAND_REGEX = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
const HEX_PARSE_REGEX = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;

export class NcgDashboardPanel extends Polymer.PolymerElement {
	static get template() {
		return Polymer.html`
		<style include="nodecg-theme paper-material-styles">
			:host {
				display: inline-block;
				width: 128px;
			}

			:host([fullbleed]) {
				width: 100%!important;
				height: 100%!important;
			}

			:host(:not([fullbleed])) {
				@apply --paper-material-elevation-1;
			}

			:host([width="1"]) {
				width: 128px;
			}

			:host([width="2"]) {
				width: 272px;
			}

			:host([width="3"]) {
				width: 416px;
			}

			:host([width="4"]) {
				width: 560px;
			}

			:host([width="5"]) {
				width: 704px;
			}

			:host([width="6"]) {
				width: 848px;
			}

			:host([width="7"]) {
				width: 992px;
			}

			:host([width="8"]) {
				width: 1136px;
			}

			:host([width="9"]) {
				width: 1280px;
			}

			:host([width="10"]) {
				width: 1424px;
			}

			#header {
				position: relative;
				color: var(--google-grey-100);
				@apply --layout-horizontal;
				@apply --layout-end-justified;
				@apply --layout-center;
				@apply --layout-flex-none;
				@apply --paper-font-title;
				overflow: hidden;
			}

			#header a {
				color: inherit;
			}

			#displayTitle {
				position: absolute;
				left: 15px;
				top: 6px;
			}

			#buttons {
				@apply --layout-horizontal;
				@apply --layout-center;
				padding-left: 8px;
				transform: translateX(100%);
				transition: transform 200ms ease;
			}

			#more {
				position: absolute;
				right: 10px;
				top: 8px;
			}

			#buttonsContainer {
				z-index: 1;
			}

			#header:hover #buttons {
				transform: translateX(0%);
			}

			#dragHandle {
				cursor: -webkit-grab;
				cursor: -moz-grab;
				cursor: grab;
			}

			#dragHandle:active {
				cursor: -webkit-grabbing;
				cursor: -moz-grabbing;
				cursor: grabbing;
			}

			#body {
				min-height: 1px;
				padding: 0;
				background-color: #f5f5f5;
			}

			paper-icon-button[hidden] {
				/* For whatever reason, paper-icon-button doesn't specify its own [hidden] style.
				   https://github.com/PolymerElements/paper-icon-button/issues/103 */
				display: none !important;
			}

			:host([fullbleed]) {
				@apply --layout-vertical;
			}

			/* When fullbleed, buttons are always visible */
			:host([fullbleed]) #buttons {
				transform: translateX(0%);
			}

			:host([fullbleed]) #collapse {
				@apply --layout-flex;
				@apply --layout-vertical;
			}

			:host([fullbleed]) #body {
				@apply --layout-flex;
			}

			:host([fullbleed]) ::slotted(iframe) {
				height: 100%;
			}
		</style>

		<iron-localstorage name="{{computeLocalStorageName(bundle, panel)}}" value="{{opened}}" on-iron-localstorage-load-empty="initializeDefaultOpened"></iron-localstorage>

		<div id="header">
			<span id="displayTitle">[[displayTitle]]</span>
			<div id="buttonsContainer">
				<iron-icon id="more" icon="chevron-left"></iron-icon>
				<div id="buttons">
					<a href="[[standaloneUrl]]" target="_blank">
						<paper-icon-button id="openStandalone" icon="open-in-new"></paper-icon-button>
					</a>

					<paper-icon-button id="expandBtn" on-click="toggleCollapse" icon="unfold-less" hidden="[[fullbleed]]"></paper-icon-button>

					<paper-icon-button id="dragHandle" icon="open-with" hidden="[[fullbleed]]"></paper-icon-button>
				</div>
			</div>
		</div>

		<iron-collapse id="collapse" opened="{{opened}}" transitioning="{{transitioning}}">
			<div id="body">
				<slot id="slot"></slot>
			</div>
		</iron-collapse>
`;
	}

	static get is() {
		return "ncg-dashboard-panel";
	}

	static get properties() {
		return {
			displayTitle: {
				type: String,
				reflectToAttribute: true,
			},
			bundle: {
				type: String,
				reflectToAttribute: true,
			},
			panel: {
				type: String,
				reflectToAttribute: true,
			},
			opened: {
				type: Boolean,
				reflectToAttribute: true,
				observer: "_openedChanged",
			},
			headerColor: {
				type: String,
				reflectToAttribute: true,
				observer: "_headerColorChanged",
			},
			width: {
				type: Number,
				reflectToAttribute: true,
			},
			transitioning: {
				type: Boolean,
				notify: true,
			},
			fullbleed: {
				type: Boolean,
				reflectToAttribute: true,
			},
		};
	}

	override ready(): void {
		super.ready();

		afterNextRender(this, async () => {
			const distributedNodes: HTMLElement[] = this.$.slot.assignedNodes({
				flatten: true,
			});
			const iframe = distributedNodes.find(
				(el) => el.tagName === "IFRAME",
			) as HTMLIFrameElement;

			// If Sentry is enabled, use it to report errors in panels to Sentry.io.
			if (window.ncgConfig.sentry.enabled) {
				const Sentry = await import("@sentry/browser");
				iframe.contentWindow!.addEventListener("error", (event) => {
					Sentry.captureException(event.error);
				});
				iframe.contentWindow!.addEventListener("unhandledrejection", (err) => {
					Sentry.captureException(err.reason);
				});
			}

			if (!this.fullbleed) {
				if (iframe.contentWindow!.document.readyState === "complete") {
					this._attachIframeResize(iframe);
				} else {
					iframe.addEventListener("load", () => {
						this._attachIframeResize(iframe);
					});
				}
			}
		});
	}

	_attachIframeResize(iframe: HTMLIFrameElement) {
		initialize(
			{
				onIframeResize: (context) => {
					this.$.collapse.updateSize("auto", false);
					context.iframe.dispatchEvent(new CustomEvent("iframe-resized"));
				},
			},
			iframe,
		);
	}

	override connectedCallback(): void {
		super.connectedCallback();

		const { src } = this.querySelector("iframe")!;
		this.standaloneUrl = `${src}?standalone=true`;
	}

	toggleCollapse() {
		this.$.collapse.toggle();
	}

	initializeDefaultOpened() {
		this.opened = true;
	}

	_openedChanged(newVal: boolean) {
		this.$.expandBtn.icon = newVal ? "unfold-less" : "unfold-more";
	}

	_headerColorChanged(newVal: string) {
		this.$.header.style.backgroundColor = newVal;
		this.$.buttons.style.background = this._calcLinearGradient(
			this._hexToRGB(newVal)!,
		);
	}

	computeLocalStorageName(bundle: string, panel: string) {
		return [bundle, panel, "opened"].join(".");
	}

	_calcLinearGradient(rgb: { r: number; g: number; b: number }) {
		const rgbStr = `${rgb.r}, ${rgb.g}, ${rgb.b}`;
		return `linear-gradient(to right, rgba(${rgbStr}, 0) 0px,rgba(${rgbStr}, 1) 10px)`;
	}

	/* istanbul ignore next: tseems to confuse coverage */
	_hexToRGB(hex: string) {
		// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
		hex = hex.replace(
			HEX_PARSE_SHORTHAND_REGEX,
			(_m, r, g, b) => r + r + g + g + b + b,
		);

		const result = HEX_PARSE_REGEX.exec(hex);
		return result
			? {
					r: parseInt(result[1]!, 16),
					g: parseInt(result[2]!, 16),
					b: parseInt(result[3]!, 16),
				}
			: null;
	}
}

customElements.define("ncg-dashboard-panel", NcgDashboardPanel);
