import {DataPlane, DataSource, RecordDataSource} from '../DataPlane'
import {FieldDefinition, FieldType} from '../types'
import {Unsubscribe} from '../../BehaviorSubject'

export type FormErrors = Record<string, string[]>

export type FormState = {
    dirty: boolean
    valid: boolean
    errors: FormErrors
}

export class FormStateManager {
    private sub?: Unsubscribe

    constructor(
        private readonly fields: FieldDefinition[],
        private readonly formSource: string,
        private readonly stateSource: string,
        private readonly plane: DataPlane,
    ) {
        this.sub = this.plane.getAll(this.formSource)
            ?.subscribe(formData =>
                this.rebuildState(formData))

        this.rebuildState()
    }

    private rebuildState(formData?: Record<string, unknown>) {
        if ( !formData ) {
            this.plane
                .getAll(this.stateSource)
                ?.next({ dirty: false, errors: {} })

            return
        }

        const errors = this.updateValidation(formData)
        this.plane
            .getAll(this.stateSource)
            ?.next({
                dirty: true,
                valid: !Object.keys(errors).length,
                errors,
            })
    }

    private updateValidation(formData: Record<string, unknown>): FormErrors {
        const errors: FormErrors = {}

        for ( const field of this.fields ) {
            const value = formData[field.key]

            if (
                field.required
                && !value
                && (
                    (
                        field.type !== FieldType.integer
                        && field.type !== FieldType.number
                    )
                    || value !== 0
                )
            ) {
                if ( !errors[field.key] ) errors[field.key] = []
                errors[field.key]!.push(`${field.display} is required.`)
            }

            if (
                value
                && field.type === FieldType.email
                && !(/^\S+@\S+\.\S+$/.test(String(value)))
            ) {
                if ( !errors[field.key] ) errors[field.key] = []
                errors[field.key]!.push(`${field.display} must be a valid email address.`)
            }

            if (
                (value || value === 0)
                && (
                    field.type === FieldType.integer
                    || field.type === FieldType.number
                )
                && (
                    typeof value !== 'number'
                    || isNaN(value)
                )
            ) {
                if ( !errors[field.key] ) errors[field.key] = []
                errors[field.key]!.push(`${field.display} must be a valid ${field.type}`)
            }

            if (
                value
                && field.type === FieldType.date
                && (
                    !(value instanceof Date)
                    || isNaN(value.getTime())
                )
            ) {
                if ( !errors[field.key] ) errors[field.key] = []
                errors[field.key]!.push(`${field.display} must be a valid date`)
            }
        }

        return errors
    }
}
