import { consume } from '@lit/context';
import type { TemplateResult } from 'lit';
import { css, html, LitElement, nothing, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { pluralize } from '@gitlens/utils/string.js';
import { proTrialLengthInDays, SubscriptionState } from '../../../../constants.subscription.js';
import type { Source } from '../../../../constants.telemetry.js';
import type { Subscription, SubscriptionUpgradeCommandArgs } from '../../../../plus/gk/models/subscription.js';
import {
	getSubscriptionProductPlanName,
	getSubscriptionTimeRemaining,
	isSubscriptionPaid,
	isSubscriptionTrial,
} from '../../../../plus/gk/utils/subscription.utils.js';
import { createCommandLink } from '../../../../system/commands.js';
import type { PromosContext } from '../contexts/promos.js';
import { promosContext } from '../contexts/promos.js';
import type { GlPopover } from './overlays/popover.js';
import { focusOutline } from './styles/lit/a11y.css.js';
import { elementBase, linkBase } from './styles/lit/base.css.js';
import './overlays/popover.js';
import './overlays/tooltip.js';
import './promo.js';

declare global {
	interface HTMLElementTagNameMap {
		'gl-feature-badge': GlFeatureBadge;
	}

	// interface GlobalEventHandlersEventMap {}
}

@customElement('gl-feature-badge')
export class GlFeatureBadge extends LitElement {
	static override styles = [
		elementBase,
		linkBase,
		css`
			:host {
				/* position: relative; */
				display: inline-block;
				--gl-feature-badge-color: currentcolor;
				--gl-feature-badge-border-color: var(--color-foreground--50);
				--max-width: 40rem;
			}

			a {
				color: var(--color-link);
				text-decoration: underline;
			}

			.badge {
				display: inline-block;
				padding: 0 0.8rem 0.1rem;
				font-size: var(--gl-feature-badge-font-size, x-small);
				font-weight: 600;
				font-variant: all-small-caps;
				color: var(--gl-feature-badge-color, currentColor);
				white-space: nowrap;
				cursor: help;
				border: var(--gl-border-width) solid var(--gl-feature-badge-border-color, var(--color-foreground--50));
				border-radius: 1rem;
			}

			.badge:focus-visible {
				${unsafeCSS(focusOutline)}
			}

			.badge-icon {
				margin-left: var(--gl-space-4);
				font-weight: 400;
				white-space: nowrap;
			}

			.badge-popup {
				display: flex;
				flex-direction: column;
				gap: var(--gl-space-6);
				white-space: normal;
			}

			.popup-header {
				display: flex;
				flex-direction: column;
				margin-bottom: var(--gl-space-4);
			}

			.popup-title {
				font-size: var(--gl-font-base);
				font-weight: 600;
			}

			.popup-subtitle {
				margin-top: var(--gl-space-6);
				font-size: smaller;
			}

			.popup-content {
				display: flex;
				flex-direction: column;
				padding-top: var(--gl-space-6);
				border-top: var(--gl-border-width) solid var(--color-foreground--25);
			}

			.popup-content p {
				margin: 0;
			}

			.popup-content .actions {
				margin-top: var(--gl-space-8);
				margin-bottom: var(--gl-space-6);
			}

			.popup-content .actions:first-child {
				margin-bottom: var(--gl-space-8);
			}

			.popup-content .actions :not(:first-child) {
				margin-top: var(--gl-space-4);
			}

			.popup-content .actions gl-button:not(:first-child) {
				margin-top: var(--gl-space-8);
			}

			.hint {
				border-bottom: var(--gl-border-width) dashed currentcolor;
			}
		`,
	];

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

	@property({ reflect: true })
	placement: GlPopover['placement'] = 'bottom';

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

	@consume({ context: promosContext })
	private promos!: PromosContext;

	@property({ type: Object })
	source?: Source;

	@property({ attribute: false })
	subscription?: Subscription;

	private get daysRemaining() {
		if (this.subscription == null) return 0;

		return getSubscriptionTimeRemaining(this.subscription, 'days') ?? 0;
	}

	private get state() {
		return this.subscription?.state;
	}

	override render(): unknown {
		return html`
			<gl-popover placement=${this.placement}>
				<span slot="anchor" class="badge" tabindex="0">${this.renderBadge()}</span>
				<div slot="content" class="badge-popup" tabindex="-1">
					${this.renderPopoverHeader()}${this.renderPopoverContent()}
				</div>
			</gl-popover>
		`;
	}

	private renderBadge() {
		const text = this.preview ? 'Preview' : 'Pro';

		if (this.subscription != null) {
			if (this.state === SubscriptionState.VerificationRequired) {
				return html`${text} <code-icon class="badge-icon" icon="warning" size="10"></code-icon>`;
			} else if (isSubscriptionPaid(this.subscription) || (this.cloud && this.subscription.account != null)) {
				return html`${text} <code-icon class="badge-icon" icon="check" size="10"></code-icon>`;
			} else if (isSubscriptionTrial(this.subscription)) {
				return html`${text} <code-icon class="badge-icon" icon="clock" size="10"></code-icon>`;
			}
		}

		return text;
	}

	private renderPopoverHeader() {
		const text = html`<span class="popup-title">${this.preview ? 'Preview feature' : 'Pro feature'}</span>`;

		if (this.state === SubscriptionState.Paid) {
			return html`<div class="popup-header">${text}</div>`;
		}

		if (this.cloud) {
			if (this.preview) {
				return html`<div class="popup-header">
					${text}<span class="popup-subtitle"
						>Unlock this feature with an account and may require GitLens Pro in the future</span
					>
				</div>`;
			}

			return html`<div class="popup-header">
				${text}<span class="popup-subtitle"> Unlock this feature with GitLens Pro</span>
			</div>`;
		}

		if (this.preview) {
			return html`<div class="popup-header">
				${text}<span class="popup-subtitle">May require GitLens Pro in the future</span>
			</div>`;
		}

		return html`<div class="popup-header">
			${text}<span class="popup-subtitle"> Unlock this feature for privately hosted repos with GitLens Pro</span>
		</div>`;
	}

	private renderPopoverContent() {
		if (this.subscription == null) return nothing;

		let content;
		switch (this.state) {
			case SubscriptionState.Paid:
				content = html`<p>
					Your
					<gl-tooltip content="Show Account view">
						<a href="${createCommandLink('gitlens.showAccountView')}"
							>${getSubscriptionProductPlanName(this.subscription?.plan.actual.id ?? 'pro')}</a
						>
					</gl-tooltip>
					plan provides access to all Pro features.
				</p>`;
				break;

			case SubscriptionState.VerificationRequired:
				content = html`<p>You must verify your email before you can access Pro features.</p>
					<div class="actions">
						<gl-button
							density="tight"
							href="${createCommandLink<Source>('gitlens.plus.resendVerification', this.source)}"
							>Resend Email</gl-button
						>
						<gl-button
							appearance="secondary"
							density="tight"
							href="${createCommandLink<Source>('gitlens.plus.validate', this.source)}"
							><code-icon icon="refresh"></code-icon
						></gl-button>
					</div>`;
				break;

			case SubscriptionState.Trial: {
				const days = this.daysRemaining;

				content = html`<p>
						You have
						<strong>${days < 1 ? '<1 day' : pluralize('day', days, { infix: ' more ' })} left</strong>
						in your Pro trial. Once your trial ends, you will only be able to use Pro features on
						publicly-hosted repos.
					</p>
					${this.renderUpgradeActions()}`;
				break;
			}

			case SubscriptionState.TrialExpired:
				content = html`<p>
						Your Pro trial has ended. You can now only use Pro features on publicly-hosted repos.
					</p>
					${this.renderUpgradeActions(
						html`<p>Please upgrade for full access to all GitLens Pro features:</p>`,
					)}`;
				break;

			case SubscriptionState.TrialReactivationEligible:
				content = html`<p>
						Reactivate your Pro trial and experience all the new Pro features — free for another
						${pluralize('day', proTrialLengthInDays)}!
					</p>
					<div class="actions center">
						<gl-button
							density="tight"
							href="${createCommandLink<Source>('gitlens.plus.reactivateProTrial', this.source)}"
							tooltip="Reactivate your Pro trial for another ${pluralize('day', proTrialLengthInDays)}"
							>Reactivate Pro Trial</gl-button
						>
					</div>`;
				break;

			default:
				content = html`<p>
						You only have access to
						<gl-tooltip content="Pro features that do not require an account"
							><span class="hint">local</span></gl-tooltip
						>
						Pro features on publicly-hosted repos.
					</p>
					${this.renderStartTrialActions()}`;
				break;
		}

		return html`<div class="popup-content">${content}</div>`;
	}

	private renderStartTrialActions() {
		return html`<div class="actions">
			<p>For access to all Pro features:</p>
			<gl-button density="tight" href="${createCommandLink<Source>('gitlens.plus.signUp', this.source)}"
				>Start ${proTrialLengthInDays}-day Pro Trial</gl-button
			>
			&nbsp;or
			<a href="${createCommandLink<Source>('gitlens.plus.login', this.source)}" title="Sign In">sign in</a>
		</div>`;
	}

	private renderUpgradeActions(leadin?: TemplateResult) {
		return html`<div class="actions">
			${leadin ?? nothing}
			<gl-button
				density="tight"
				href="${createCommandLink<SubscriptionUpgradeCommandArgs>('gitlens.plus.upgrade', {
					plan: 'pro',
					...(this.source ?? { source: 'feature-badge' }),
				})}"
				>Upgrade to Pro</gl-button
			>
			${this.renderPromo()}
		</div>`;
	}

	private renderPromo() {
		return html`<gl-promo
			.promoPromise=${this.promos.getApplicablePromo(undefined, 'badge')}
			.source=${this.source}
		></gl-promo>`;
	}
}
