// @ts-strict-ignore
import { Component, effect, Input, OnInit, ChangeDetectionStrategy } from "@angular/core";
import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms";
import { ModalController } from "@ionic/angular";
import { TranslateService } from "@ngx-translate/core";
import { LiveDataService } from "src/app/edge/live/livedataservice";
import { DataService } from "src/app/shared/components/shared/dataservice";
import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from "src/app/shared/shared";
import { FormUtils } from "src/app/shared/utils/form/form.utils";

type mode = "ON" | "AUTOMATIC" | "OFF";
type inputMode = "SOC" | "GRIDSELL" | "GRIDBUY" | "PRODUCTION" | "OTHER";

@Component({
    selector: "oe-controller-io-channelsinglethreshold-modal",
    templateUrl: "./modal.component.html",
    standalone: false,
    changeDetection: ChangeDetectionStrategy.Eager,
    providers: [{ provide: DataService, useClass: LiveDataService }],
})
export class Controller_Io_ChannelSingleThresholdModalComponent implements OnInit {
    @Input({ required: true }) public edge!: Edge;
    @Input({ required: true }) public config!: EdgeConfig;
    @Input({ required: true }) public component!: EdgeConfig.Component;
    @Input() public outputChannel: ChannelAddress | null = null;
    @Input({ required: true }) public inputChannel!: ChannelAddress;
    @Input() public inputChannelUnit: string | null = null;

    public formGroup: FormGroup;

    public loading: boolean = false;

    public minimumSwitchingTime = null;
    public threshold = null;
    public switchedLoadPower = null;
    public inputMode = null;
    public invert: number | null = null;

    constructor(
        public service: Service,
        public modalCtrl: ModalController,
        public translate: TranslateService,
        public websocket: Websocket,
        public formBuilder: FormBuilder,
        private dataService: DataService,
    ) {
        effect(() => {
            const currValue = dataService.currentValue();
            const invert =
                currValue.allComponents[new ChannelAddress(this.component.id, "_PropertyInvert").toString()] == 1;

            const formControl = FormUtils.findFormControlSafely(this.formGroup, "invert");
            if (!formControl.dirty) {
                this.formGroup.controls["invert"].setValue(invert);
            }
        });
    }

    ngOnInit() {
        this.formGroup = this.formBuilder.group({
            minimumSwitchingTime: new FormControl(
                this.component.properties.minimumSwitchingTime,
                Validators.compose([Validators.min(5), Validators.pattern("^[1-9][0-9]*$"), Validators.required]),
            ),
            switchedLoadPower: new FormControl(
                this.component.properties.switchedLoadPower,
                Validators.compose([Validators.pattern("^(?:[1-9][0-9]*|0)$"), Validators.required]),
            ),
            threshold: new FormControl(
                this.getInputMode() == "GRIDSELL"
                    ? this.component.properties.threshold * -1
                    : this.component.properties.threshold,
                Validators.compose([Validators.min(1), Validators.pattern("^[1-9][0-9]*$"), Validators.required]),
            ),
            inputMode: new FormControl(this.getInputMode()),
            invert: new FormControl(null, Validators.requiredTrue),
        });
        this.minimumSwitchingTime = this.formGroup.controls["minimumSwitchingTime"];
        this.threshold = this.formGroup.controls["threshold"];
        this.switchedLoadPower = this.formGroup.controls["switchedLoadPower"];
        this.inputMode = this.formGroup.controls["inputMode"];
        this.invert = this.component.properties["invert"];

        this.dataService.subscribeChannels([new ChannelAddress(this.component.id, "_PropertyInvert")], this.edge, "");
    }

    public updateInputMode(event: CustomEvent) {
        let newThreshold: number = this.component.properties.threshold;

        switch (event.detail.value) {
            case "SOC":
                this.inputMode.setValue("SOC");
                this.switchedLoadPower.setValue(0);
                this.switchedLoadPower.markAsDirty();
                if (
                    Math.abs(this.component.properties.threshold) < 0 ||
                    Math.abs(this.component.properties.threshold) > 100
                ) {
                    newThreshold = 50;
                    this.threshold.setValue(newThreshold);
                    this.threshold.markAsDirty();
                } else if (this.component.properties.threshold < 0) {
                    this.threshold.setValue(newThreshold);
                    this.threshold.markAsDirty();
                }
                break;
            case "GRIDSELL":
                this.inputMode.setValue("GRIDSELL");
                this.threshold.markAsDirty();
                this.switchedLoadPower.markAsDirty();
                break;
            case "GRIDBUY":
                this.inputMode.setValue("GRIDBUY");
                this.switchedLoadPower.markAsDirty();
                if (this.component.properties.threshold < 0) {
                    newThreshold = this.formGroup.value.threshold;
                    this.threshold.setValue(newThreshold);
                    this.threshold.markAsDirty();
                }
                break;
            case "PRODUCTION":
                this.inputMode.setValue("PRODUCTION");
                this.switchedLoadPower.setValue(0);
                this.switchedLoadPower.markAsDirty();
                if (this.component.properties.threshold < 0) {
                    newThreshold = this.threshold.value;
                    this.threshold.setValue(newThreshold);
                    this.threshold.markAsDirty();
                }
                break;
        }
    }

    public updateMode(event: CustomEvent) {
        const oldMode = this.component.properties.mode;
        let newMode: mode;

        switch (event.detail.value) {
            case "ON":
                newMode = "ON";
                break;
            case "OFF":
                newMode = "OFF";
                break;
            case "AUTOMATIC":
                newMode = "AUTOMATIC";
                break;
        }

        if (this.edge != null) {
            this.edge
                .updateComponentConfig(this.websocket, this.component.id, [{ name: "mode", value: newMode }])
                .then(() => {
                    this.component.properties.mode = newMode;
                    this.service.toast(this.translate.instant("GENERAL.CHANGE_ACCEPTED"), "success");
                })
                .catch((reason) => {
                    this.component.properties.mode = oldMode;
                    this.service.toast(
                        this.translate.instant("GENERAL.CHANGE_FAILED") + "\n" + reason.error.message,
                        "danger",
                    );
                    console.warn(reason);
                });
        }
    }

    public applyChanges(): void {
        if (this.edge != null) {
            if (this.edge.roleIsAtLeast("owner")) {
                if (this.minimumSwitchingTime.valid && this.threshold.valid && this.switchedLoadPower.valid) {
                    if (this.threshold.value > this.switchedLoadPower.value) {
                        const updateComponentArray = [];
                        Object.keys(this.formGroup.controls).forEach((element, index) => {
                            if (this.formGroup.controls[element].dirty) {
                                // catch inputMode and convert it to inputChannelAddress
                                if (Object.keys(this.formGroup.controls)[index] == "inputMode") {
                                    updateComponentArray.push({
                                        name: "inputChannelAddress",
                                        value: this.convertToChannelAddress(this.formGroup.controls[element].value),
                                    });
                                } else if (
                                    this.inputMode.value == "GRIDSELL" &&
                                    Object.keys(this.formGroup.controls)[index] == "threshold"
                                ) {
                                    this.formGroup.controls[element].setValue(
                                        this.formGroup.controls[element].value * -1,
                                    );
                                    updateComponentArray.push({
                                        name: Object.keys(this.formGroup.controls)[index],
                                        value: this.formGroup.controls[element].value,
                                    });
                                } else {
                                    updateComponentArray.push({
                                        name: Object.keys(this.formGroup.controls)[index],
                                        value: this.formGroup.controls[element].value,
                                    });
                                }
                            }
                        });
                        this.loading = true;
                        this.edge
                            .updateComponentConfig(this.websocket, this.component.id, updateComponentArray)
                            .then(() => {
                                this.component.properties.minimumSwitchingTime = this.minimumSwitchingTime.value;
                                this.component.properties.threshold =
                                    this.inputMode.value == "GRIDSELL"
                                        ? this.threshold.value * -1
                                        : this.threshold.value;
                                this.component.properties.switchedLoadPower = this.switchedLoadPower.value;
                                this.component.properties.inputChannelAddress =
                                    this.convertToChannelAddress(this.inputMode.value) !=
                                    this.component.properties.inputChannelAddress
                                        ? this.convertToChannelAddress(this.inputMode.value)
                                        : this.component.properties.inputChannelAddress;
                                this.loading = false;
                                this.service.toast(this.translate.instant("GENERAL.CHANGE_ACCEPTED"), "success");
                            })
                            .catch((reason) => {
                                this.loading = false;
                                this.minimumSwitchingTime.setValue(this.component.properties.minimumSwitchingTime);
                                this.threshold.setValue(this.component.properties.threshold);
                                this.switchedLoadPower.setValue(this.component.properties.switchedLoadPower);
                                this.inputMode.setValue(
                                    this.convertToInputMode(
                                        this.component.properties.inputChannelAddress,
                                        this.component.properties.threshold,
                                    ),
                                );
                                this.loading = false;
                                this.service.toast(
                                    this.translate.instant("GENERAL.CHANGE_FAILED") + "\n" + reason.error.message,
                                    "danger",
                                );
                                console.warn(reason);
                            });
                        if (this.inputMode.value == "GRIDSELL") {
                            if (this.inputMode.dirty || this.threshold.dirty) {
                                this.threshold.setValue(this.threshold.value * -1);
                            }
                        }
                        this.formGroup.markAsPristine();
                    } else {
                        this.service.toast(
                            this.translate.instant("EDGE.INDEX.WIDGETS.SINGLETHRESHOLD.RELATION_ERROR"),
                            "danger",
                        );
                    }
                } else {
                    this.service.toast(this.translate.instant("GENERAL.INPUT_NOT_VALID"), "danger");
                }
            } else {
                this.service.toast(this.translate.instant("GENERAL.INSUFFICIENT_RIGHTS"), "danger");
            }
        }
    }

    private getInputMode(): inputMode {
        if (
            this.component.properties.inputChannelAddress == "_sum/GridActivePower" &&
            this.component.properties.threshold < 0
        ) {
            return "GRIDSELL";
        } else if (
            this.component.properties.inputChannelAddress == "_sum/GridActivePower" &&
            this.component.properties.threshold > 0
        ) {
            return "GRIDBUY";
        } else if (this.component.properties.inputChannelAddress == "_sum/ProductionActivePower") {
            return "PRODUCTION";
        } else if (this.component.properties.inputChannelAddress == "_sum/EssSoc") {
            return "SOC";
        } else if (this.component.properties.inputChannelAddress != null) {
            return "OTHER";
        }
    }

    private convertToChannelAddress(inputMode: inputMode): string | null {
        switch (inputMode) {
            case "SOC":
                return "_sum/EssSoc";
            case "GRIDBUY":
                return "_sum/GridActivePower";
            case "GRIDSELL":
                return "_sum/GridActivePower";
            case "PRODUCTION":
                return "_sum/ProductionActivePower";
            default:
                return null;
        }
    }

    private convertToInputMode(inputChannelAddress: string, threshold: number): inputMode {
        switch (inputChannelAddress) {
            case "_sum/EssSoc":
                return "SOC";
            case "_sum/ProductionActivePower":
                return "PRODUCTION";
            case "_sum/GridActivePower":
                if (threshold > 0) {
                    return "GRIDBUY";
                } else if (threshold < 0) {
                    return "GRIDSELL";
                }
        }
    }
}
