import { createStyleMixin, draggableMixin, componentNameValidationMixin } from '../../mixins';
import { compose } from '../../helpers';
import { getComponentName } from '../../helpers/componentHelpers';
import { createBaseInputClass } from '../../baseClasses/createBaseInputClass';
import { ButtonClass } from '@descope-ui/descope-button/class';
import { getFileBase64, getFilename } from './helpers';
import { injectStyle } from '@descope-ui/common/components-helpers';

export const componentName = getComponentName('upload-file');

const observedAttributes = [
  'title',
  'description',
  'button-label',
  'accept',
  'readonly',
  'button-mode',
  'button-variant',
  'required',
  'size',
  'icon',
];

const BaseInputClass = createBaseInputClass({ componentName, baseSelector: ':host > div' });

class RawUploadFile extends BaseInputClass {
  static get observedAttributes() {
    return observedAttributes.concat(BaseInputClass.observedAttributes || []);
  }

  constructor() {
    super();

    this.attachShadow({ mode: 'open' }).innerHTML = `
			<div>
        <slot name="icon"></slot>
				<div class="title">
					<span class="title-text"></span>
				</div>
				<div class="description"></div>
				<div class="button-wrapper">
					<input type="file" tabindex="-1" aria-labelledby="button"/>
					<descope-button id="button"></descope-button>
				</div>
			</div>
		`;

    injectStyle(
      `
      :host {
				display: flex;
			}
			:host > div {
				display: flex;
				align-items: center;
				justify-content: center;
				text-align: center;
				flex-direction: column;
				width: 100%;
			}
			.button-wrapper {
				position: relative;
				width: fit-content;
			}
			input {
				position: absolute;
				width: 100%;
				height: 100%;
				opacity: 0;
			}
        `,
      this
    );

    this.wrapperEle = this.shadowRoot.querySelector('.wrapper');
    this.inputElement = this.shadowRoot.querySelector('input');

    this.button.onclick = () => this.inputElement.click();

    this.inputElement.onchange = async (e) => {
      const receivedFileList = e.target.files;

      if (!receivedFileList.length) {
        return;
      }

      this.value = await getFileBase64(receivedFileList[0]);

      this.updateDescription(getFilename(receivedFileList[0]));
    };

    this.oninvalid = () => {
      this.setAttribute('invalid', 'true');
    };
  }

  // this is a temp solution,
  // we should show the input error message like we have in all other inputs
  /*
  reportValidity() {
    this.defaultReportValidity();
  }
  */

  getValidity() {
    if (this.isRequired && !this.input.value) {
      return { valueMissing: true };
    }
    this.removeAttribute('invalid');
    return {};
  }

  initInputs() {
    const button = this.rootElement.querySelector('descope-button');
    button.onclick = () => this.inputElement.click();
  }

  attributeChangedCallback(attrName, oldValue, newValue) {
    super.attributeChangedCallback?.(attrName, oldValue, newValue);

    if (oldValue !== newValue) {
      if (attrName === 'title') {
        this.updateTitle(newValue);
      } else if (attrName === 'description') {
        this.updateDescription(newValue);
      } else if (attrName === 'button-label') {
        this.updateButtonLabel(newValue);
      } else if (attrName === 'button-mode') {
        this.updateButtonMode(newValue);
      } else if (attrName === 'button-variant') {
        this.updateButtonVariant(newValue);
      } else if (attrName === 'size') {
        this.updateButtonSize(newValue);
      } else if (attrName === 'accept') {
        this.updateInputAccept(newValue);
      } else if (attrName === 'readonly') {
        this.updateReadOnly(newValue);
      }
    }
  }

  get button() {
    return this.shadowRoot.querySelector('descope-button');
  }

  get input() {
    return this.shadowRoot.querySelector('input');
  }

  get title() {
    return this.shadowRoot.querySelector('.title-text');
  }

  get description() {
    return this.shadowRoot.querySelector('.description');
  }

  get icon() {
    return this.shadowRoot.querySelector('.icon');
  }

  updateTitle(val) {
    this.title.textContent = val;
  }

  updateDescription(val) {
    this.description.textContent = val;
  }

  updateButtonLabel(val) {
    this.button.textContent = val;
  }

  updateButtonSize(val) {
    this.button.setAttribute('size', val);
  }

  updateButtonMode(val) {
    this.button.setAttribute('mode', val);
  }

  updateButtonVariant(val) {
    this.button.setAttribute('variant', val);
  }

  updateInputAccept(val) {
    this.input.setAttribute('accept', val);
  }

  updateReadOnly(val) {
    if (val === 'true') {
      this.input.setAttribute('disabled', 'true');
    } else {
      this.input.removeAttribute('disabled');
    }
  }
}

const buttonVars = ButtonClass.cssVarList;
const { host, wrapper, icon, title, description, requiredIndicator } = {
  host: { selector: () => ':host' },
  wrapper: { selector: () => ':host > div' },
  icon: { selector: () => '::slotted(*)' },
  title: { selector: () => '.title' },
  description: { selector: () => '.description' },
  requiredIndicator: { selector: () => '.title::after' },
};

export const UploadFileClass = compose(
  createStyleMixin({ componentNameOverride: getComponentName('input-wrapper') }),
  createStyleMixin({
    mappings: {
      fontSize: {},
      fontFamily: {},
      borderColor: {},
      borderWidth: {},
      borderStyle: {},
      borderRadius: {},
      hostHeight: { ...host, property: 'height' },
      hostWidth: { ...host, property: 'width' },
      hostPadding: { property: 'padding' },
      hostDirection: [
        { ...host, property: 'direction' },
        { selector: () => ButtonClass.componentName, property: buttonVars.hostDirection },
      ],
      gap: { ...wrapper },
      lineHeight: { ...wrapper, property: 'line-height' },
      titleFontSize: { ...title, property: 'font-size' },
      titleFontWeight: { ...title, property: 'font-weight' },
      descriptionFontSize: { ...description, property: 'font-size' },
      labelTextColor: [
        { ...title, property: 'color' },
        { ...description, property: 'color' },
      ],
      iconSize: { ...icon, property: 'width' },
      requiredIndicator: { ...requiredIndicator, property: 'content' },
    },
  }),
  draggableMixin,
  componentNameValidationMixin
)(RawUploadFile);
