import { observer } from "mobx-react";
import { createViewModel, IViewModel } from "mobx-utils";
import * as React from "react";
import { RouteComponentProps } from "react-router";
import { Button, CheckboxProps, Form, Input, InputOnChangeData, Menu, Modal, Segment } from "semantic-ui-react";

import { ProgramSequenceView, ScheduleView } from "@app/components";
import * as rp from "@app/routePaths";
import { AppState, injectState } from "@app/state";
import log from "@common/logger";
import { Program, SprinklersDevice } from "@common/sprinklersRpc";

@observer
class ProgramPage extends React.Component<{
    appState: AppState,
} & RouteComponentProps<{ deviceId: string, programId: number }>, {
    programView: Program & IViewModel<Program> | undefined,
}> {
    private device!: SprinklersDevice;
    private program!: Program;

    constructor(p: any) {
        super(p);
        this.state = {
            programView: undefined,
        };
    }

    get isEditing(): boolean {
        return this.state.programView != null;
    }

    renderName(program: Program) {
        const { name } = program;
        if (this.isEditing) {
            return (
                <Menu.Item header>
                    <Form>
                        <Form.Group inline>
                            <Form.Field inline>
                                <label><h4>Program</h4></label>
                                <Input
                                    placeholder="Program Name"
                                    type="text"
                                    value={name}
                                    onChange={this.onNameChange}
                                />
                            </Form.Field>
                            ({program.id})
                        </Form.Group>
                    </Form>
                </Menu.Item>
            );
        } else {
            return <Menu.Item header as="h4">Program {name} ({program.id})</Menu.Item>;
        }
    }

    renderActions(program: Program) {
        const { running } = program;
        const editing = this.isEditing;
        let editButtons;
        if (editing) {
            editButtons = (
                <React.Fragment>
                    <Button primary onClick={this.save}>
                        Save
                    </Button>
                    <Button negative onClick={this.cancelEditing}>
                        Cancel
                    </Button>
                </React.Fragment>
            );
        } else {
            editButtons = (
                <Button primary onClick={this.startEditing}>
                    Edit
                </Button>
            );
        }
        return (
            <Modal.Actions>
                <Button positive={!running} negative={running} onClick={this.cancelOrRun}>
                    {running ? "Stop" : "Run"}
                </Button>
                {editButtons}
                <Button onClick={this.close}>
                    Close
                </Button>
            </Modal.Actions>
        );
    }

    render() {
        const { deviceId, programId } = this.props.match.params;
        const device = this.device = this.props.appState.sprinklersRpc.getDevice(deviceId);
        // TODO: check programId
        if (device.programs.length <= programId || !device.programs[programId]) {
            return null;
        }
        this.program = device.programs[programId];

        const { programView } = this.state;
        const program = programView || this.program;
        const editing = programView != null;

        const { running, enabled, schedule, sequence } = program;

        return (
            <Modal open onClose={this.close} className="programEditor">
                <Modal.Header>{this.renderName(program)}</Modal.Header>
                <Modal.Content>
                    <Form>
                        <Form.Group>
                            <Form.Checkbox
                                toggle
                                label="Enabled"
                                checked={enabled}
                                readOnly={!editing}
                                onChange={this.onEnabledChange}
                            />
                            <Form.Checkbox toggle label="Running" checked={running} readOnly={!editing}/>
                        </Form.Group>
                        <Form.Field>
                            <label><h4>Sequence</h4></label>
                            <ProgramSequenceView sequence={sequence} sections={this.device.sections} editing={editing}/>
                        </Form.Field>
                        <Form.Field>
                            <label><h4>Schedule</h4></label>
                            <ScheduleView schedule={schedule}/>
                        </Form.Field>
                    </Form>
                </Modal.Content>
                {this.renderActions(program)}
            </Modal>
        );
    }

    private cancelOrRun = () => {
        if (!this.program) {
            return;
        }
        this.program.running ? this.program.cancel() : this.program.run();
    }

    private startEditing = () => {
        let { programView } = this.state;
        if (programView) { // stop editing, so save
            programView.submit();
            programView = undefined;
        } else { // start editing
            programView = createViewModel(this.program);
        }
        this.setState({ programView });
    }

    private save = () => {
        let { programView } = this.state;
        if (programView) { // stop editing, so save
            programView.submit();
            programView = undefined;
        }
        this.setState({ programView });
        this.program.update()
            .then((data) => {
                log.info({ data }, "Program updated");
            }, (err) => {
                log.error({ err }, "error updating Program");
            });
    }

    private cancelEditing = () => {
        let { programView } = this.state;
        if (programView) {
            programView = undefined; // stop editing
        }
        this.setState({ programView });
    }

    private close = () => {
        const { deviceId } = this.props.match.params;
        this.props.history.push({ pathname: rp.device(deviceId) });
    }

    private onNameChange = (e: any, p: InputOnChangeData) => {
        const { programView } = this.state;
        if (programView) {
            programView.name = p.value;
        }
    }

    private onEnabledChange = (e: any, p: CheckboxProps) => {
        const { programView } = this.state;
        if (programView) {
            programView.enabled = p.checked!;
        }
    }
}

const DecoratedProgramPage = injectState(observer(ProgramPage));
export default DecoratedProgramPage;
