import type { VNode } from 'vue';
import type { DropdownButtonItemArgs } from '../dropdown-button/dropdown-button-item';
import type { FormItemWrapperArgs, MarginType } from '../form/form-item-wrapper';
import { Prop, toNative } from 'vue-facing-decorator';
import TsxComponent, { Component } from '../../app/vuetsx';
import { PortalUtils } from '../../common/utils/utils';
import FormItemWrapper from '../form/form-item-wrapper';
import HtmlLiteral from '../html-literal/html-literal';
import './css/checkbox.css';

interface CheckBoxArgs extends Omit<FormItemWrapperArgs, 'errorId'> {
	name?: string;
	value: boolean;
	checkboxLabelHtml?: string;
	customRenderOption?: (h, state: CheckBoxDisplayArgs) => any;
	skin?: CheckBoxSkin;
	size?: CheckBoxSize;
	disabled?: boolean;
	changed?: (newValue: boolean) => void;
}

export enum CheckBoxSkin {
	NowUi = 0,
	Material = 1, // default
	MinusVariant = 2,
}

export enum CheckBoxSize {
	Small = 'sm',
	Medium = 'md',
}

interface CheckBoxDisplayArgs {
	checked: boolean;
	disabled: boolean;
}

@Component
class CheckBoxComponent extends TsxComponent<CheckBoxArgs> implements CheckBoxArgs {
	@Prop() name?: string;
	@Prop() label!: string | VNode;
	@Prop() labelButtons!: DropdownButtonItemArgs[];
	@Prop() cssClass!: string;
	@Prop() subtitle!: string;
	@Prop() checkboxLabelHtml!: string;
	@Prop() customRenderOption?: (h, state: CheckBoxDisplayArgs) => any;
	@Prop() value!: boolean;
	@Prop() mandatory!: boolean;
	@Prop() wrap!: boolean;
	@Prop() maxWidth?: number;
	@Prop() skin!: CheckBoxSkin;
	@Prop() size?: CheckBoxSize;
	@Prop() disabled?: boolean;
	@Prop() marginType?: MarginType;
	@Prop() hint: string;
	@Prop() appendIcon: string;
	@Prop() prependIcon: string;
	@Prop() appendClicked: () => void;
	@Prop() prependClicked: () => void;
	@Prop() changed: (newValue: boolean) => void;
	uuid: string = null;

	private get errorId(): string {
		return `checkbox-error-${this.$.uid}`;
	}

	getCustomRenderedLabel(h) {
		if (this.customRenderOption != null) {
			const displayArgs: CheckBoxDisplayArgs = {
				checked: this.value,
				disabled: this.disabled ?? false,
			};

			return this.customRenderOption(h, displayArgs);
		}

		return null;
	}

	raiseChangeEvent(e) {
		this.populateValidationDeclaration();
		const val = e.target.checked;

		if (this.changed != null) {
			this.changed(val);
		}
	}

	render(h) {
		return (
			<FormItemWrapper
				label={this.label}
				cssClass={this.cssClass}
				mandatory={this.mandatory}
				wrap={this.wrap}
				appendIcon={this.appendIcon}
				prependIcon={this.prependIcon}
				marginType={this.marginType}
				hint={this.hint}
				appendClicked={this.appendClicked}
				prependClicked={this.prependClicked}
				maxWidth={this.maxWidth}
				validationState={this.validationState}
				labelButtons={this.labelButtons}
				subtitle={this.subtitle}
				errorId={this.errorId}
			>
				{this.renderCheckboxBasedOnSkin(h)}
			</FormItemWrapper>
		);
	}

	renderCheckboxBasedOnSkin(h) {
		if (this.skin == CheckBoxSkin.NowUi) {
			return this.renderCheckboxNowUi(h);
		} else if (this.skin == CheckBoxSkin.MinusVariant) {
			return this.renderCheckboxMaterialMinus(h);
		}

		// default -> CheckBoxSkin.Material
		return this.renderCheckboxMaterial(h);
	}

	renderCheckboxNowUi(h) {
		const checkboxClass = `form-check ${this.wrap ? 'ui-checkbox-wrapped' : 'ui-checkbox-nonwrapped'
			}${this.size === CheckBoxSize.Small ? ' ui-checkbox-sm' : ''}`;

		return (
			<div class={checkboxClass}>
				<label class="form-check-label">
					<input class="form-check-input" type="checkbox" checked={this.value} disabled={this.disabled || undefined} onChange={e => this.raiseChangeEvent(e)} name={this.name} aria-invalid={this.hasValidationError ? 'true' : undefined} aria-describedby={this.hasValidationError ? this.errorId : undefined} aria-required={this.mandatory ? 'true' : undefined} />
					<span class="form-check-sign"></span>
					{this.getCustomRenderedLabel(h) ?? this.checkboxLabelHtml}
				</label>
			</div>
		);
	}

	renderCheckboxMaterial(h) {
		if (this.uuid == null) {
			this.uuid = PortalUtils.randomString(12);
		}

		const checkboxClass = `inv-md-checkbox${this.size === CheckBoxSize.Small ? ' inv-md-checkbox-sm' : ''}`;

		return (
			<div class={checkboxClass}>
				<div class="inv-cbrb-inner">
					<input class="inv-chckb-clickable" type="checkbox" id={`iei-input-${this.uuid}`} checked={this.value} disabled={this.disabled || undefined} onChange={e => this.raiseChangeEvent(e)} name={this.name} aria-invalid={this.hasValidationError ? 'true' : undefined} aria-describedby={this.hasValidationError ? this.errorId : undefined} aria-required={this.mandatory ? 'true' : undefined} />
					<label class="inv-chckb-clickable form-check-label " for={`iei-input-${this.uuid}`}>
						{this.getCustomRenderedLabel(h) ?? <HtmlLiteral innerHTML={this.checkboxLabelHtml} />}
					</label>
				</div>
			</div>
		);
	}

	renderCheckboxMaterialMinus(h) {
		if (this.uuid == null) {
			this.uuid = PortalUtils.randomString(12);
		}

		const checkboxClass = `inv-md-checkbox${this.size === CheckBoxSize.Small ? ' inv-md-checkbox-sm' : ''
			}${this.skin === CheckBoxSkin.MinusVariant ? ' inv-md-checkbox-minus' : ''}`;

		return (
			<div class={checkboxClass}>
				<div class="inv-cbrb-inner">
					<input class="inv-chckb-clickable" type="checkbox" id={`iei-input-${this.uuid}`} checked={this.value} disabled={this.disabled || undefined} onChange={e => this.raiseChangeEvent(e)} name={this.name} aria-invalid={this.hasValidationError ? 'true' : undefined} aria-describedby={this.hasValidationError ? this.errorId : undefined} aria-required={this.mandatory ? 'true' : undefined} />
					<label class="inv-chckb-clickable form-check-label " for={`iei-input-${this.uuid}`}>
						{this.getCustomRenderedLabel(h) ?? <HtmlLiteral innerHTML={this.checkboxLabelHtml} />}
					</label>
				</div>
			</div>
		);
	}
}

const CheckBox = toNative(CheckBoxComponent);
export default CheckBox;
