import { css, html, LitElement, nothing } from 'lit';
import { customElement, property, query } from 'lit/decorators.js';
import { getAltKeySymbol } from '@env/platform.js';
import { ModifierKeysController } from '../../controllers/modifier-keys.js';
import { focusOutline } from '../styles/lit/a11y.css.js';
import '../overlays/tooltip.js';
import '../code-icon.js';

@customElement('action-item')
export class ActionItem extends LitElement {
	static override shadowRootOptions: ShadowRootInit = {
		...LitElement.shadowRootOptions,
		delegatesFocus: true,
	};

	static override styles = css`
		:host {
			box-sizing: border-box;
			display: inline-flex;
			align-items: center;
			justify-content: center;
			width: 2rem;
			height: 2rem;
			padding: var(--gl-space-2);
			vertical-align: text-bottom;
			color: var(--action-item-foreground, var(--vscode-icon-foreground));
			text-decoration: none;
			cursor: pointer;
			border-radius: var(--gl-radius-sm);
		}

		.icon-wrapper {
			position: relative;
			display: inline-flex;
			align-items: center;
			justify-content: center;
		}

		code-icon[part~='icon-outline'] {
			position: absolute;
			inset: 0;
			display: none;
			pointer-events: none;
		}

		:host(:focus-within) {
			${focusOutline}
		}

		:host(:hover),
		:host(:focus-within) {
			background-color: var(--action-item-hover-background, var(--vscode-toolbar-hoverBackground));
		}

		:host(:active) {
			background-color: var(--action-item-active-background, var(--vscode-toolbar-activeBackground));
		}

		:host([disabled]) {
			pointer-events: none;
			opacity: 0.5;
		}

		a {
			display: flex;
			align-items: center;
			justify-content: center;
			width: 100%;
			height: 100%;
			color: inherit;
			text-decoration: none;
		}

		a:focus {
			outline: none;
		}

		a:is(:hover, :focus, :active) {
			text-decoration: none;
		}
	`;

	@property()
	href?: string;

	@property({ attribute: 'alt-href' })
	altHref?: string;

	@property()
	label?: string;

	@property({ attribute: 'alt-label' })
	altLabel?: string;

	@property()
	icon = '';

	@property({ attribute: 'alt-icon' })
	altIcon?: string;

	@property({ attribute: 'outline-icon' })
	outlineIcon?: string;

	@property({ type: Boolean })
	disabled = false;

	@query('a')
	private defaultFocusEl!: HTMLAnchorElement;

	private readonly _modifiers = new ModifierKeysController(this);

	private get isAltKeyPressed(): boolean {
		return this._modifiers.altKey || this._modifiers.shiftKey;
	}

	get effectiveIcon(): string {
		if (this.isAltKeyPressed && this.altIcon) {
			return this.altIcon;
		}
		return this.icon;
	}

	get effectiveTooltip(): string | undefined {
		if (!this.label && !this.altLabel) {
			return undefined;
		}
		if (this.altLabel) {
			if (this.isAltKeyPressed) {
				return this.altLabel;
			}
			return `${this.label}\n[${getAltKeySymbol()}] ${this.altLabel}`;
		}
		return this.label;
	}

	get effectiveLabel(): string | undefined {
		if (!this.label && !this.altLabel) {
			return undefined;
		}
		if (this.altLabel && this.isAltKeyPressed) {
			return this.altLabel;
		}
		return this.label;
	}

	get effectiveHref(): string | undefined {
		if (this.isAltKeyPressed && this.altHref) {
			return this.altHref;
		}
		return this.href;
	}

	override render(): unknown {
		return html`
			<gl-tooltip content="${this.effectiveTooltip ?? nothing}">
				<a
					role="${!this.effectiveHref ? 'button' : nothing}"
					type="${!this.effectiveHref ? 'button' : nothing}"
					aria-label="${this.effectiveLabel ?? nothing}"
					?disabled=${this.disabled}
					href=${this.effectiveHref ?? nothing}
					tabindex="0"
					@keydown=${this.handleLinkKeydown}
				>
					<span class="icon-wrapper">
						<code-icon part="icon" icon="${this.effectiveIcon}"></code-icon>
						<code-icon
							part="icon-outline"
							icon="${this.outlineIcon ?? this.effectiveIcon}"
							aria-hidden="true"
						></code-icon>
					</span>
				</a>
			</gl-tooltip>
		`;
	}

	private handleLinkKeydown = (e: KeyboardEvent) => {
		// Handle Space and Enter for button-role links without href.
		if (!this.effectiveHref && (e.key === ' ' || e.key === 'Enter')) {
			e.preventDefault();
			// Dispatch a synthetic click that carries the current modifier state so consumers
			// reading `MouseEvent.altKey` (e.g. the WIP smart Open Multi-Diff button) work for
			// keyboard activation too — `HTMLElement.click()` would synthesize a click with all
			// modifiers false.
			(e.target as HTMLElement).dispatchEvent(
				new MouseEvent('click', {
					bubbles: true,
					cancelable: true,
					composed: true,
					altKey: e.altKey,
					ctrlKey: e.ctrlKey,
					metaKey: e.metaKey,
					shiftKey: e.shiftKey,
				}),
			);
		}
	};

	override focus(options?: FocusOptions): void {
		this.defaultFocusEl.focus(options);
	}
}
