import {Component} from '../../vues6.js'
import {Status} from './Listing.component.js'
import {Resource, ResourceActions} from '../Resource.js'
import {uuid} from '../util.js'

const template = `
<div class="card shadow mb-4 col-lg-6 offset-lg-3" style="padding: 0">
    <div class="card-header py-3">
        {{ title }}
    </div>
    <div class="card-body">
        <div v-if="status === 'loading'">Loading...</div>
        <form v-if="status === 'ready'">
            <div class="form-group" v-for="field of fields">
                <input
                    v-if="field.type === 'bool'"
                    class="form-check-inline"
                    type="checkbox"
                    :name="field.key"
                    v-model="data[field.key]"
                    :id="id + field.key"
                    :aria-describedby="id + field.key + '_help'"
                    :readonly="mode === 'view' || field.readonly"
                    :required="field.required"
                >
                <label for="id + field.key">{{ field.display }}</label>
                <input
                    v-if="field.type === 'text' || field.type === 'email' || field.type === 'number' || field.type === 'integer' || !field.type"
                    :type="field.type || 'text'"
                    class="form-control"
                    :name="field.key"
                    v-model="data[field.key]"
                    :required="field.required"
                    :id="id + field.key"
                    :aria-describedby="id + field.key + '_help'"
                    :placeholder="field.placeholder || ''"
                    :readonly="mode === 'view' || field.readonly"
                    :step="field.type === 'number' ? 'any' : undefined"
                >
                <textarea
                    class="form-control"
                    v-if="field.type === 'textarea'"
                    v-model="data[field.key]"
                    :name="field.key"
                    :id="id + field.key"
                    :aria-describedby="id + field.key + '_help'"
                    :placeholder="field.placeholder || ''"
                    :readonly="mode === 'view' || field.readonly"
                    :required="field.required"
                    rows="10"
                ></textarea>
                <input
                    v-if="field.type === 'date' && (mode === 'view' || field.readonly)"
                    class="form-control"
                    :name="field.key"
                    :value="data[field.key].toDisplay()"
                    :required="field.required"
                    :id="id + field.key"
                    :aria-describedby="id + field.key + '_help'"
                    :placeholder="field.placeholder || ''"
                    :readonly="mode === 'view' || field.readonly"
                >
                <select
                    class="form-control"
                    size="10"
                    v-if="field.type === 'select'"
                    :multiple="!!field.multiple"
                    v-model="data[field.key]"
                >
                    <option v-for="option of field.options" :value="option.value">{{ option.display }}</option>
                </select>
                <cobalt-monaco
                    v-if="field.type === 'html' && !(mode === 'view' || field.readonly)"
                    syntax="html"
                    :initialvalue="data[field.key]"
                    @changed="value => data[field.key] = value"
                ></cobalt-monaco>
                <div
                    v-if="field.type === 'html' && (mode === 'view' || field.readonly)"
                    v-html="data[field.key]"
                ></div>
                <DatePicker
                    v-model="data[field.key]"
                    v-if="field.type === 'date' && !(mode === 'view' || field.readonly)"
                    :type="field.renderer || 'date'"
                    :id="id + field.key"
                    :aria-describedby="id + field.key + '_help'"
                    :clearable="!field.required"
                    input-class="form-control"
                    style="display: inherit !important; width: 100%;"
                ></DatePicker>
                <small
                    class="form-text text-muted"
                    :id="id + field.key + '_help'"
                    v-if="field.helpText"
                >{{ field.helpText }}</small>
                <small
                    class="form-text"
                    style="color: darkred"
                    :id="id + field.key + '_error'"
                    v-if="errors[field.key]"
                >{{ errors[field.key] }}</small>
            </div>
            <div style="display: flex; justify-content: end">
                <div
                    class="text-muted"
                    style="padding: 5px; margin-right: 20px"
                >{{ statusMessage }}</div>
                <cobalt-action-button
                    :action="{overall: true, color: 'secondary', icon: 'fa-angle-left', title: 'Cancel', type: 'back'}"
                    style="margin-right: 10px !important;"
                ></cobalt-action-button>
                <button
                    v-if="mode === 'edit'"
                    class="btn btn-primary btn-icon-split"
                    type="button"
                    @click="save"
                >
                    <span class="icon text-white-50">
                        <i class="fas fa-save"></i>
                    </span>
                    <span class="text">Save</span>
                </button>
                <button
                    v-if="mode === 'insert'"
                    class="btn btn-success btn-icon-split"
                    type="button"
                    @click="save"
                >
                    <span class="icon text-white-50">
                        <i class="fas fa-plus"></i>
                    </span>
                    <span class="text">Create</span>
                </button>
            </div>
        </form>
    </div>
</div>
`
export class FormComponent extends Component {
    static get selector() { return 'cobalt-form' }
    static get template() { return template }
    static get props() { return ['resourcekey', 'resourceid', 'resourcemode'] }

    constructor() {
        super()

        this.status = Status.loading
        this.title = 'Loading...'
        this.statusMessage = 'Loading...'
        this.fields = []
        this.data = {}
        this.actions = []
        this.unregister = []
        this.mode = 'edit'
        this.id = uuid()
        this.internalResourceId = 0
        this.errors = {}

        /** @var {Resource} */
        this.resource = undefined
    }

    async vue_on_create() {
        this.resource = await Resource.get(this.resourcekey)
        this.title = this.resource.singular()
        this.mode = this.resourcemode || this.mode
        this.internalResourceId = this.resourceid || this.internalResourceId

        if ( !this.resource.supports(ResourceActions.readOne) ) {
            this.status = Status.errorUnsupported
        }

        await this.load()

        console.log('form', this)
    }

    async load() {
        this.data = this.internalResourceId ? await this.resource.readOne(this.internalResourceId) : {}
        this.fields = [...this.resource.configuration.fields].filter(f => {
            return !(f.hideOn && f.hideOn.form)
        })

        this.fields.forEach(field => {
            if ( field.type === 'date' && this.data[field.key] ) {
                this.data[field.key] = new Date(this.data[field.key])
            }
        })

        if ( this.resource.configuration.display.field ) {
            this.title = this.resource.singular()
            if ( this.internalResourceId ) this.title = `${this.title}: ${this.data[this.resource.configuration.display.field]}`
        }

        this.status = Status.ready
        this.statusMessage = ''
    }

    onMonacoChange(field, data, args) {
        console.log('on monaco change', {field, data, args})
        this.data[field.key] = args[0]
        console.log('after save', this.data)
    }

    async save() {
        if ( !this.validate() ) return;

        this.statusMessage = 'Saving...'

        const values = {}
        this.fields.forEach(field => {
            let value = this.data[field.key]
            const isUndef = !value && !(['integer', 'number'].includes(field.type) && value === 0) && (field.type !== 'bool')
            if ( isUndef ) return;

            if ( field.type === 'number' ) value = parseFloat(String(value))
            if ( field.type === 'integer' ) value = parseInt(String(value), 10)
            if ( field.type === 'date' ) value = value.toISOString()
            if ( field.type === 'bool' ) value = !!value

            values[field.key] = value
        })

        try {
            if (this.internalResourceId) {
                await this.resource.update(this.internalResourceId, values)
            } else {
                const result = await this.resource.create(values)
                this.internalResourceId = result[this.resource.configuration.primaryKey]
                history.replaceState({}, document.getElementsByTagName('title')[0].innerText, `${location.protocol}//${location.host}/dash/cobalt/form/${this.resource.key}/${this.internalResourceId}`)
            }

            await this.load()

            this.statusMessage = `${this.resource.singular()} ${this.mode === 'insert' ? 'created' : 'saved'}`
            this.mode = 'edit'
            setTimeout(() => this.statusMessage = '', 7000)
        } catch (e) {
            console.error(e)
            this.statusMessage = 'An unknown error occurred while saving'
        }
    }

    validate() {
        let pass = true
        this.fields.forEach(field => this.errors[field.key] = undefined)

        this.fields.forEach(field => {
            // FIXME select

            const value = this.data[field.key]
            const isUndef = !value && !(['integer', 'number'].includes(field.type) && value === 0) && (field.type !== 'bool')
            if ( field.required && isUndef ) {
                this.errors[field.key] = 'This field is required'
                pass = false
                return
            }

            if ( field.type === 'date' && !isUndef && isNaN(value.getHours()) ) {
                this.errors[field.key] = `Invalid ${field.renderer || 'date'}`
                pass = false
                return
            }

            if ( field.type === 'number' && !isUndef && isNaN(parseFloat(String(value))) ) {
                this.errors[field.key] = 'Invalid number'
                pass = false
                return
            }

            if ( field.type === 'integer' && !isUndef && (isNaN(parseInt(String(value), 10)) || parseFloat(String(value)) !== parseInt(String(value), 10)) ) {
                this.errors[field.key] = 'Invalid integer'
                pass = false
                return
            }
        })

        this.$nextTick(() => this.$forceUpdate())
        return pass
    }
}
