import { Component, EventEmitter, Input, Output, SimpleChanges, TemplateRef, ViewChild } from '@angular/core';
import { FormGroup, NonNullableFormBuilder, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzSelectItemInterface } from 'ng-zorro-antd/select';
import { horizontalInOut } from '../../../../../common.animation';
import { CommonNzModule } from '../../../../../common.nz.module';
import { ApiService } from '../../../../../services/api.service';
import { BasicDataService } from '../../../../../services/basic.service';
import { KnowledgeService } from '../../../../../services/knowledge.service';
import { SettingService } from '../../../../../services/setting.service';
import { CustomDrawerComponent } from '../../../../../shared/custom-drawer/custom-drawer.component';
import { DataSelectComponent } from '../../../../../shared/data-select/data-select.component';
import { DocSelectComponent } from '../../../../../shared/doc-select/doc-select.component';
import { docCategories, docLevels } from '../../risk-doc/risk-doc.utils';

@Component({
  selector: 'risk-item-form',
  standalone: true,
  imports: [CommonNzModule, CustomDrawerComponent, DocSelectComponent],
  templateUrl: './risk-item-form.component.html',
  styleUrl: './risk-item-form.component.less',
  animations: [horizontalInOut],
})
export class RiskItemFormComponent {
  @ViewChild('dataSelect') dataSelect!: DataSelectComponent;
  @ViewChild('tlpUpdateReason') tlpUpdateReason!: TemplateRef<HTMLDivElement>;
  docLevels = docLevels;
  docCategories = docCategories;
  @Input() config: {
    visible: boolean;
    data: Knowledge.RiskItem | null;
    type: 'add' | 'edit';
  } = {
    visible: false,
    data: null,
    type: 'add',
  };
  @Output() onClose = new EventEmitter<void>();
  @Output() fetch = new EventEmitter<void>();
  updateReason = '';
  options = {
    consequences: [] as Option[],
    level: ['R1', 'R2', 'R2*', 'R3', 'R4'].map(s => ({ label: s, value: s })),
    category: [] as Option[],
    type: [] as Option[],
    job: [] as Option[],
    position: [] as Option[],
    operation: [] as Option[],
    equipment: [] as Option[],
  };
  constructor(
    private modal: NzModalService,
    private fb: NonNullableFormBuilder,
    private knowledge: KnowledgeService,
    private message: NzMessageService,
    private basic: BasicDataService,
    private setting: SettingService,
    private api: ApiService
  ) {}
  validateForm: FormGroup = this.fb.group({
    title: this.fb.control<string>('', [Validators.required, Validators.maxLength(1000)]),
    consequences: this.fb.control<string[]>([], []),
    responsiblePerson: this.fb.control<string>('', []),
    level: this.fb.control<string>('', [Validators.required]),
    category: this.fb.control<number | null>(null, [Validators.required]),
    type: this.fb.control<number | null>(null, [Validators.required]),
    involvedPositions: this.fb.control<number[]>([], []),
    involvedEquipments: this.fb.control<number[]>([], []),
    involvedOperations: this.fb.control<number[]>([], []),
    responsiblePositions: this.fb.control<number[]>([], []),
    specificUnit: this.fb.control<string>('', []),
    requirement: this.fb.control<string>('', [Validators.maxLength(1000)]),
    otherMeasure: this.fb.control<string>('', [Validators.maxLength(1000)]),
    regulations: this.fb.control<number[]>([], []),
  });

  listOfEventControl: Array<{
    id: number;
    nameInstance: string;
    descInstance: string;
    resultInstance: string;
  }> = [];

  insideDrawerVisible = false;
  selectedDocList: number[] = [];
  get selectDocDtoList() {
    return this.selectedDocList.map(e => ({
      value: e,
      label: this.docList.find(doc => doc.id === e)?.name || '',
    }));
  }
  docList: Knowledge.Doc[] = [];
  get convertDocList() {
    return this.docList.map(e => ({ label: e.name, value: e.id }));
  }
  ngOnInit() {
    this.setOptions();
  }
  setOptions() {
    this.options.type = this.knowledge.types().map(item => ({
      label: item.value,
      value: item.id,
    }));
    this.options.level = this.knowledge.levels().map(item => ({
      label: item.value,
      value: item.value,
    }));
    this.options.consequences = this.basic.consequences.map(item => ({
      label: item.value,
      value: item.id,
    }));
    this.options.operation = this.getTargetOptions('operation');
    this.options.position = this.getTargetOptions('position');
    this.options.equipment = this.getTargetOptions('equipment');
    this.setJobOptions();
  }
  setJobOptions() {
    this.currentCategory = this.getCurrentCategory();
    if (!this.currentCategory) {
      this.options.job = [];
      this.currentDepartments = [];
      return;
    }
    this.currentDepartments = this.getSelectedDepartments();
    this.options.job = this.basic.jobs
      .filter(j => this.currentCategory!.departments.includes(j.department))
      .map(item => ({
        label: this.basic.getJobName(item.id),
        value: item.id,
      }));
  }

  getOptions(rawList: (BasicData.Operation | BasicData.Operation | BasicData.Equipment)[]) {
    const { type, category } = this.validateForm.value;
    if (!type || !category) return [];
    const filtered = rawList.filter(item => {
      let isMatch = true;

      if (isMatch && type) {
        isMatch = item.type === type;
      }
      if (isMatch && category) {
        isMatch = item.category === category;
      }
      return isMatch;
    });
    return filtered.map(item => ({
      label: item.name,
      value: item.id,
    }));
  }
  getTargetOptions(key: 'operation' | 'position' | 'equipment') {
    switch (key) {
      case 'position':
        return this.getOptions(this.basic.positions);
      case 'operation':
        return this.getOptions(this.basic.operations);
      case 'equipment':
        return this.getOptions(this.basic.equipments);
    }
  }

  changeType(value: number) {
    this.options.category = this.knowledge.getCategoryOptionsByType(value);
    this.validateForm.patchValue({
      category: null,
      involvedOperations: [],
      involvedEquipments: [],
      involvedPositions: [],
      responsiblePositions: [],
    });
    this.options.operation = this.getTargetOptions('operation');
    this.options.position = this.getTargetOptions('position');
    this.options.equipment = this.getTargetOptions('equipment');
  }
  changeCategory() {
    this.validateForm.patchValue({
      involvedOperations: [],
      involvedEquipments: [],
      involvedPositions: [],
      responsiblePositions: [],
    });
    setTimeout(() => {
      this.options.operation = this.getTargetOptions('operation');
      this.options.position = this.getTargetOptions('position');
      this.options.equipment = this.getTargetOptions('equipment');
      this.setJobOptions();
    });
  }
  closeInsideDrawer() {
    this.insideDrawerVisible = false;
  }
  openInsideDrawer() {
    this.insideDrawerVisible = true;
  }

  relatedFilter = (input?: string, option?: NzSelectItemInterface) => {
    if (!input) return true;
    return (option?.nzLabel as string).includes(input);
  };

  async selectDocument() {
    this.openInsideDrawer();
    if (this.docList.length === 0) this.message.info('未检索到文档');
  }

  ngOnChanges(changes: SimpleChanges) {
    this.setOptions();
    this.updateReason = '';
    if (changes['config']) {
      this.clearForm();
      if (this.config.data) {
        this.fillOutForm();
      }
      this.fetchDocList();
    }
  }
  fillOutForm() {
    if (!this.config.data) return;
    const {
      title,
      type,
      category,
      involvedEquipments,
      involvedOperations,
      involvedPositions,
      responsiblePerson,
      level,
      consequences,
      responsiblePositions,
      requirement,
      otherMeasure,
      regulations,
      associations,
      specificUnit,
    } = this.config.data;
    this.validateForm.patchValue({
      ...this.config.data,
      title,
      type,
      category,
      consequences,
      involvedPositions,
      involvedEquipments,
      involvedOperations,
      responsiblePerson,
      level,
      responsiblePositions,
      requirement,
      otherMeasure,
      regulations,
      specificUnit,
    });
    this.dataSelect.updateCheckDto(regulations);
    this.updateDocs(
      regulations.map(rId => this.docList.find(doc => doc.id === rId)).filter(Boolean) as Knowledge.Doc[]
    );

    if (!associations || associations.length === 0) return;
    associations.forEach((i, index) => {
      this.onEventAdd({
        title: associations[index].title,
        desc: associations[index].content,
        result: associations[index].consequence,
      });
    });
  }
  clearForm() {
    this.validateForm.reset();
    this.listOfEventControl.forEach(i => {
      this.onEventRemove(i.id);
    });
    this.listOfEventControl = [];
  }
  async fetchDocList() {
    this.docList = await this.api.knowledge.getAllDoc(this.setting.userCompany);
  }
  onEventAdd(dto?: { title: string; desc: string; result: string }) {
    const id =
      this.listOfEventControl.length > 0 ? this.listOfEventControl[this.listOfEventControl.length - 1].id + 1 : 0;
    const control = {
      id,
      nameInstance: `name-${id}`,
      descInstance: `desc-${id}`,
      resultInstance: `result-${id}`,
    };
    const index = this.listOfEventControl.push(control);
    this.validateForm.addControl(
      this.listOfEventControl[index - 1].nameInstance,
      this.fb.control(dto?.title, {
        validators: [Validators.required],
      })
    );
    this.validateForm.addControl(
      this.listOfEventControl[index - 1].descInstance,
      this.fb.control(dto?.desc, {
        validators: [Validators.required],
      })
    );
    this.validateForm.addControl(
      this.listOfEventControl[index - 1].resultInstance,
      this.fb.control(dto?.result, {
        validators: [Validators.required],
      })
    );
  }
  onEventRemove(id: number) {
    const index = this.listOfEventControl.findIndex(item => item.id === id);
    this.validateForm.removeControl(this.listOfEventControl[index].nameInstance);
    this.validateForm.removeControl(this.listOfEventControl[index].descInstance);
    this.validateForm.removeControl(this.listOfEventControl[index].resultInstance);
    this.listOfEventControl.splice(index, 1);
  }
  updateDocs(ops: Knowledge.Doc[]) {
    this.selectedDocList = ops.map(e => e.id);
    this.validateForm.patchValue({
      regulations: ops.map(e => e.id),
    });
    this.validateForm.get('regulations')?.updateValueAndValidity();
  }
  getFormValue(): Partial<Knowledge.RiskItem> {
    const v = this.validateForm.value;
    const result: Partial<Knowledge.RiskItem> = {
      company: this.setting.userCompany,
      title: v.title,
      type: v.type,
      category: v.category,
      involvedPositions: v.involvedPositions,
      involvedEquipments: v.involvedEquipments,
      involvedOperations: v.involvedOperations,
      responsiblePerson: v.responsiblePerson,
      level: v.level,
      consequences: v.consequences,
      responsiblePositions: v.responsiblePositions,
      requirement: v.requirement,
      otherMeasure: v.otherMeasure,
      regulations: v.regulations,
      specificUnit: v.specificUnit,
    };
    result.associations = [];
    this.listOfEventControl.forEach(ev => {
      result.associations?.push({
        title: this.validateForm.get(ev.nameInstance)?.value || '',
        content: this.validateForm.get(ev.descInstance)?.value || '',
        consequence: this.validateForm.get(ev.resultInstance)?.value || '',
      });
    });
    return result;
  }
  async submitForm() {
    if (!this.validateForm.valid) {
      Object.values(this.validateForm.controls).forEach(control => {
        if (control.invalid) {
          control.markAsDirty();
          control.updateValueAndValidity({ onlySelf: true });
        }
      });
    } else {
      this.onSubmit();
    }
  }
  async onSubmit() {
    const v = this.getFormValue();
    if (this.config.type === 'edit') {
      await this.queryUpdateReason(v);
    } else {
      await this.onCreate(v);
    }
  }
  async onCreate(v: Partial<Knowledge.RiskItem>) {
    await this.api.knowledge.createRiskItem(v).then(res => {
      if (!res.code) {
        this.message.success('创建成功');
        this.onClose.emit();
        this.fetch.emit();
      } else {
        this.message.error('创建失败:' + res.message);
      }
    });
  }
  async onUpdate(v: Partial<Knowledge.RiskItem>) {
    await this.api.knowledge
      .updateRiskItem({
        ...v,
        id: this.config.data?.id,
      })
      .then(res => {
        if (!res.code) {
          this.message.success('更新成功');
          this.onClose.emit();
          this.fetch.emit();
        } else {
          this.message.error('更新失败:' + res.message);
        }
      });
  }
  handleCancel() {
    this.onClose.emit();
  }
  get confirmText() {
    return this.config.type === 'add' ? '创建' : '更新';
  }

  queryUpdateReason(v: Partial<Knowledge.RiskItem>) {
    this.modal.create({
      nzTitle: '更新原因',
      nzContent: this.tlpUpdateReason,
      nzClassName: 'precaution-modal',
      nzClosable: false,
      nzOnOk: () => this.onUpdate({ ...v, updateReason: this.updateReason }),
    });
  }
  currentCategory?: Knowledge.RiskCategoryDto;
  getCurrentCategory() {
    const { category, type } = this.validateForm.value;
    const currentType = this.knowledge.types().find(t => t.id === type);
    if (!currentType) return undefined;
    return currentType.categories.find(c => c.id === category);
  }
  currentDepartments: BasicData.Department[] = [];
  getSelectedDepartments() {
    if (!this.currentCategory) return [];
    return (this.currentDepartments = this.basic.departments.filter(d =>
      this.currentCategory!.departments.includes(d.id)
    ));
  }
}
