import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, MaxLength } from 'class-validator';
import { CreateDto } from 'src/common/dto/create.dto';
import { PaginationDTO } from 'src/assessment-evaluation/dto/pagination.dto';
import { DevicePartOperation } from 'src/train/entities/device/device-part-operation.entity';
import { DevicePartHasOperation } from 'src/train/entities/device/device-part-has-operation.entity';
import { Device } from 'src/train/entities/device/device.entity';
import { DeviceIP } from 'src/train/entities/device/device-ip.entity';
import { DevicePartsService } from './device-parts.service';
import { DeviceParts } from 'src/train/entities/device/device-parts.entity';

@Injectable()
export class DeviceService {
  constructor(
    @InjectRepository(DevicePartOperation)
    private devicePartOperation: Repository<DevicePartOperation>,
    @InjectRepository(DevicePartHasOperation)
    private devicePartHasOperation: Repository<DevicePartHasOperation>,
    @InjectRepository(Device)
    private Device: Repository<Device>,
    @InjectRepository(DeviceIP)
    private DeviceIP: Repository<DeviceIP>,
    @InjectRepository(DeviceParts)
    private deviceParts: Repository<DeviceParts>,

    private devicePartsService: DevicePartsService,
  ) {}
  /**
   * 创建设备
   * @param createClassifyDto
   * @returns
   */
  async create(createDeviceDto: CreateDeviceDto, token: any) {
    const userId = token.userId;
    // await this.Device.query('START TRANSACTION');
    // try {
    const device = await this.Device.save(createDeviceDto, {
      transaction: false,
    });
    const ips = createDeviceDto.ips;
    if (ips.length > 0) {
      const ipsList = ips.map((item) => ({
        creator: userId,
        updater: userId,
        device: device.id,
        group: item.group,
        ip: item.ip,
        comment: item.comment,
      }));
      await this.DeviceIP.insert(ipsList);
    }
    for (let ind = 0; ind < createDeviceDto.part.length; ind++) {
      const part = createDeviceDto.part[ind];
      await this.devicePartsService.create({
        device: device.id,
        creator: userId,
        updater: userId,
        ...part,
      });
    }

    // await this.Device.query('COMMIT');
    // } catch (error) {
    //   await this.Device.query('ROLLBACK'); // 回滚事务
    //   throw error;
    // }
    return true;
  }
  /**
   * 获取所有设备，包含所有部件和所有部件状态
   * @returns
   */
  async findOperationContent(list: FindOperationContentDto) {
    const whereIs = { delFlag: 0 };
    if (list.devices && list.devices.length > 0) {
      whereIs['id'] = In(list.devices);
    }
    return this.Device.createQueryBuilder('d')
      .where(whereIs)
      .leftJoinAndMapMany('d.part', DeviceParts, 'dp', 'dp.device = d.id')
      .leftJoinAndMapMany('', DevicePartHasOperation, 'dpho', 'dpho.part=dp.id')
      .leftJoinAndMapMany(
        'dp.operation',
        DevicePartOperation,
        'dpo',
        'dpho.operation = dpo.id',
      )
      .getMany();
  }
  /**
   * 获取所有设备
   * @returns
   */
  async findAll() {
    return this.Device.find({
      where: { delFlag: 0 },
    });
  }
  async getOneById(id: number) {
    const device = await this.Device.findOneBy({ id, delFlag: 0 });
    const deviceIps = await this.DeviceIP.find({
      where: { device: id, delFlag: 0 },
    });
    const deviceParts = await this.deviceParts
      .createQueryBuilder('part')
      .where({ delFlag: 0, device: id })
      .leftJoinAndMapMany(
        '',
        DevicePartHasOperation,
        'haso',
        'haso.part = part.id',
      )
      .leftJoinAndMapMany(
        'part.operation',
        DevicePartOperation,
        'operation',
        'haso.operation = operation.id',
      )
      .andWhere('haso.del_flag=0 and operation.del_flag=0')
      .getMany();
    device['ips'] = deviceIps;
    device['part'] = deviceParts;
    return device;
  }
  /**
   * 分页获取设备
   * @returns
   */
  async pagingDetails(paging: DevicePagingDto) {
    const res: any = await this.Device
      .query(`select d.id,d.name,d.keycode,ifnull(parts.total ,0) parts,d.position,dnp.name positionName,d.groups,d.comment,d.classify from device d 
      left join device_number_position dnp on dnp.id = d.position 
      left join (
      select count(1) total, dp.device  from device_parts dp group by dp.device 
      ) parts on parts.device = d.id
      where d.del_flag =0 ${
        paging.classify != null ? 'and d.classify=' + paging.classify : ''
      } ${
      paging.name != null ? 'and d.name like' + "'%" + paging.name + "%'" : ''
    }
      order by d.id desc
    limit ${(paging.currentPage - 1) * paging.pageSize},${paging.pageSize}`);

    const [{ total }] = await this.Device.query(
      `select count(1) total from device d where d.del_flag =0 ${
        paging.classify != null ? 'and d.classify=' + paging.classify : ''
      } ${
        paging.name != null
          ? 'and d.name like ' + "'%" + paging.name + "%'"
          : ''
      }`,
    );
    return {
      data: res,
      total: total,
    };
  }
  /**
   * 分页获取设备 旧
   * @returns
   */
  async paging(paging: PaginationDTO) {
    const res: any = await this.Device.createQueryBuilder('device')
      .andWhere({
        delFlag: 0,
      })
      .orderBy('device.id', 'DESC')
      .skip((paging.currentPage - 1) * paging.pageSize)
      .take(paging.pageSize)
      .getManyAndCount();
    return {
      data: res[0],
      total: res[1],
    };
  }
  /**
   * 更新设备
   * @param id
   * @param updateClassifyDto
   * @returns
   */
  async update(id: number, updateClassifyDto: UpdateDeviceDto) {
    const userId = updateClassifyDto.creator;
    // await this.Device.query('START TRANSACTION');
    // try {
    await this.devicePartsService.removeByDevice(id);
    await this.DeviceIP.delete({ device: id });

    const ips = updateClassifyDto.ips;
    if (ips.length > 0) {
      const ipsList = ips.map((item) => ({
        creator: userId,
        updater: userId,
        device: id,
        group: item.group,
        ip: item.ip,
        comment: item.comment,
      }));
      for (let ipind = 0; ipind < ipsList.length; ipind++) {
        const ipitem = ipsList[ipind];

        await this.DeviceIP.insert(ipitem);
      }
    }
    for (let ind = 0; ind < updateClassifyDto.part.length; ind++) {
      const part = updateClassifyDto.part[ind];
      delete part['id'];
      await this.devicePartsService.create({
        device: id,
        creator: userId,
        updater: userId,
        ...part,
      });
    }
    const a = { ...updateClassifyDto };
    delete a.ips;
    delete a.part;
    await this.Device.update(id, a);
    //   await this.Device.query('COMMIT');
    // } catch (error) {
    //   await this.Device.query('ROLLBACK'); // 回滚事务
    //   throw error;
    // }
    return true;
  }
  /**
   *  删除设备
   * @param id
   * @returns
   */
  async remove(ids: number[]) {
    await this.Device.update(ids, { delFlag: 1 });
    // 删除设备时同时删除部件和状态的关联信息
    // ids.forEach(async (item) => {
    //   await this.Device.delete({ id: item });
    // });
    return true;
  }
}

export class CreateDeviceDto extends CreateDto {
  @ApiProperty({ description: '设备' })
  @IsNotEmpty({ message: '设备不能为空' })
  @MaxLength(20, { message: '设备不能超过20个字符' })
  name: string;

  @ApiProperty({ description: '设备键值' })
  @IsNotEmpty({ message: '设备键值不能为空' })
  @MaxLength(20, { message: '键值不能超过20个字符' })
  keycode: string;

  @ApiProperty({ description: '号位ID' })
  @IsNotEmpty({ message: '号位ID不能为空' })
  position: number;

  @ApiProperty({ description: '分组数量' })
  @IsNotEmpty({ message: '分组数量不能为空' })
  groups: number;

  @ApiProperty({ description: '设备说明', default: '' })
  comment: string;

  @ApiProperty({ description: '设备分类ID' })
  @IsNotEmpty({ message: '设备分类ID不能为空' })
  classify: number;

  @ApiProperty({
    description: '设备ip地址们',
    default: [{ group: 1, ip: '127.0.0.1', comment: 'ip' }],
  })
  ips?: { group: number; ip: string; comment: string }[];

  @ApiProperty({
    description: '设备部件们',
    default: [
      {
        name: '按钮x',
        keycode: 'btn_x',
        comment: '电源开关按钮',
        operation: [{ id: 0 }],
      },
    ],
  })
  part?: {
    name: string;
    keycode: string;
    comment: string;
    operation?: Array<{ id: number }>;
  }[];
}
export class UpdateDeviceDto extends CreateDto {
  @ApiProperty({ description: '设备' })
  name: string;

  @ApiProperty({ description: '设备键值' })
  keycode: string;

  @ApiProperty({ description: '号位ID' })
  position: number;

  @ApiProperty({ description: '分组数量' })
  groups: number;

  @ApiProperty({ description: '设备说明', default: '' })
  comment: string;

  @ApiProperty({ description: '设备分类ID' })
  classify: number;

  @ApiProperty({
    description: '设备ip地址们',
    default: [{ group: 1, ip: '127.0.0.1', comment: 'ip' }],
  })
  ips?: { group: number; ip: string; comment: string }[];

  @ApiProperty({
    description: '设备部件们',
    default: [
      {
        name: '按钮x',
        keycode: 'btn_x',
        comment: '电源开关按钮',
        operation: [{ id: 0 }],
      },
    ],
  })
  part?: {
    name: string;
    keycode: string;
    comment: string;
    operation?: Array<{ id: number }>;
  }[];
}

export class DevicePagingDto extends PaginationDTO {
  @ApiProperty({ description: '分类ID', required: false })
  classify?: number;

  @ApiProperty({ description: '模糊查询', required: false })
  name?: string;
}

export class FindOperationContentDto {
  @ApiProperty({ description: '设备ID列表', required: false })
  devices?: number[];
}
