import { Op } from 'sequelize';

import TrackTask, { TrackTaskCreationAttributes } from '../models/trackTask';
import TrackTaskDetail, {
  TrackTaskDetailCreationAttributes,
} from '../models/trackTaskDetail';
import sequelize from '../sequelizeInstance';
import {
  TrackTaskStatusKey,
  TrackTaskDetailStatusKey,
  TRACK_TASK_STATUS,
  TRACK_TASK_DETAIL_STATUS,
} from '../enumerate';

export async function getUnfinishTrackTask(schoolId: string) {
  const task = await TrackTask.findOne({
    where: { status: TRACK_TASK_STATUS.READY, schoolId },
  }).catch((err) => {
    console.dir(err);
  });
  return task ? task.dataValues : null;
}

export async function createTrackTask(
  data: TrackTaskCreationAttributes,
  details: TrackTaskDetailCreationAttributes[]
) {
  const t = await sequelize.transaction();

  try {
    await TrackTask.update(
      {
        status: TRACK_TASK_STATUS.FINISH,
        error: '补漏结束',
      },
      {
        where: {
          status: { [Op.ne]: TRACK_TASK_STATUS.FINISH },
          schoolId: data.schoolId,
        },
        transaction: t,
      }
    );

    // 保存任务
    const task = await TrackTask.create(data, { transaction: t });

    details.forEach((item) => {
      item.trackTaskId = task.id;
    });
    await TrackTaskDetail.bulkCreate(details, { transaction: t });

    await t.commit();

    return task.dataValues;
  } catch (error) {
    await t.rollback();
    return Promise.reject(error);
  }
}

export async function finishAllUnfinishTask(schoolId: string) {
  await TrackTask.update(
    {
      status: TRACK_TASK_STATUS.FINISH,
      error: '强制结束',
    },
    {
      where: {
        status: { [Op.ne]: TRACK_TASK_STATUS.FINISH },
        schoolId,
      },
    }
  );
}

export async function updateTrackTaskStatus(data: {
  id: number;
  status: TrackTaskStatusKey;
}) {
  await TrackTask.update(
    {
      status: TRACK_TASK_STATUS[data.status],
    },
    {
      where: {
        id: data.id,
      },
    }
  );
}

export async function createTrackTaskDetails(
  details: TrackTaskDetailCreationAttributes[]
) {
  const t = await sequelize.transaction();
  try {
    await TrackTaskDetail.bulkCreate(details, { transaction: t });
    await t.commit();

    return true;
  } catch (error) {
    await t.rollback();
    return Promise.reject(error);
  }
}

// track detail ------------------->
export async function getTrackTaskDetailCount(data: {
  trackTaskId: number;
  status?: TrackTaskDetailStatusKey;
}) {
  const count = await TrackTaskDetail.count({
    where: {
      trackTaskId: data.trackTaskId,
      ...(data.status ? { status: TRACK_TASK_DETAIL_STATUS[data.status] } : {}),
    },
  });
  return count;
}

export async function getUnfinishTrackTaskDetail(trackTaskId: number) {
  const task = await TrackTaskDetail.findOne({
    where: { status: TRACK_TASK_DETAIL_STATUS.INIT, trackTaskId },
  }).catch((err) => {
    console.dir(err);
  });
  if (!task) return null;

  await TrackTaskDetail.update(
    {
      status: TRACK_TASK_DETAIL_STATUS.RUNNING,
    },
    {
      where: {
        id: task.id,
      },
    }
  );

  return task.dataValues;
}

export async function getUnfinishTrackTaskDetails(
  trackTaskId: number,
  count = 10
) {
  const t = await sequelize.transaction();

  try {
    const limitCount = Math.max(10, Math.min(100, count));
    const rows = await TrackTaskDetail.findAll({
      where: { status: TRACK_TASK_DETAIL_STATUS.INIT, trackTaskId },
      limit: limitCount,
      transaction: t,
    });

    if (rows.length) {
      await TrackTaskDetail.update(
        {
          status: TRACK_TASK_DETAIL_STATUS.RUNNING,
        },
        {
          where: {
            id: {
              [Op.in]: rows.map((row) => row.dataValues.id),
            },
          },
          transaction: t,
        }
      );
    }

    await t.commit();

    return rows.map((row) => row.dataValues);
  } catch (error) {
    await t.rollback();
    return Promise.reject(error);
  }
}

export async function updateTrackTaskDetailStatus(data: {
  id: number;
  status: TrackTaskDetailStatusKey;
}) {
  await TrackTaskDetail.update(
    {
      status: TRACK_TASK_DETAIL_STATUS[data.status],
    },
    {
      where: {
        id: data.id,
      },
    }
  );
}

export async function releaseAllRunningTaskDetail(trackTaskId: number) {
  await TrackTaskDetail.update(
    {
      status: TRACK_TASK_DETAIL_STATUS.INIT,
    },
    {
      where: {
        status: TRACK_TASK_DETAIL_STATUS.RUNNING,
        trackTaskId,
      },
    }
  );
}

export async function releaseAllRunningTaskDetailByIds(
  trackTaskDetailIds: number[]
) {
  await TrackTaskDetail.update(
    {
      status: TRACK_TASK_DETAIL_STATUS.INIT,
    },
    {
      where: {
        status: TRACK_TASK_DETAIL_STATUS.RUNNING,
        id: {
          [Op.in]: trackTaskDetailIds,
        },
      },
    }
  );
}
