import { Request, Response } from "express";
import BoatType from "../db/models/BoatType";
import Boat from "../db/models/Boat";
import Sport from "../db/models/Sport";
import BoatHasSport from "../db/models/BoatHasSport";

//create boat
const createBoat = async (req: Request, res: Response) => {
  try {
    if (!(res.locals.user.role == "coordinator")) {
      return res
        .status(403)
        .json({ success: false, error: "MustBeCoordinator" });
    }

    const newBoatInput = req.body;

    const boatType = await BoatType.findByPk(newBoatInput.boattype);
    if (!boatType) {
      return res
        .status(404)
        .json({ success: false, error: "boattypeNotFound" });
    }

    //sport array of ids
    const sportsArray = newBoatInput.sports;
    //check wether each given id exists or not
    for (let i = 0; i < sportsArray.length; i++) {
      const found = await Sport.findByPk(sportsArray[i]);
      if (!found)
        return res
          .status(404)
          .json({ success: false, error: sportsArray[i] + " notFound" });
    }

    const newBoat = await Boat.create(newBoatInput); // create the boat

    const boatid = newBoat.id;

    //create entry (boatid, each id of given sportIds)
    for (let i = 0; i < sportsArray.length; i++) {
      const sportid = sportsArray[i];
      const entry = { boatid, sportid };
      //create new entry in boatHasBoatType
      await BoatHasSport.create(entry);
    }

    if (newBoat) {
      return res.status(201).json({
        success: true,
        result: {
          id: newBoat.id,
          name: newBoat.name,
          boattype: newBoat.boattype,
          status: newBoat.status,
          tags: newBoat.tags,
          minP: newBoat.minP,
          maxP: newBoat.maxP,
          sports: newBoat.sports,
        },
      });
    }
  } catch (error) {
    console.error(error.message);
    return res.status(500).json({ success: false, error: "serverError" });
  }
};

//show all boats
const showAllBoatsController = async (req: Request, res: Response) => {
  try {
    const allBoats = await Boat.findAll();
    return res.status(200).send({
      success: true,
      result: allBoats.map((boat) => {
        return {
          id: boat.id,
          name: boat.name,
          boattype: boat.boattype,
          status: boat.status,
          tags: boat.tags,
          minP: boat.minP,
          maxP: boat.maxP,
          sports: boat.sports,
        };
      }),
    });
  } catch (error) {
    console.error("server error: ", error.message);
    return res.status(500).json({ success: false, error: "serverError" });
  }
};

//show specific boat using given id
const showBoatById = async (req: Request, res: Response) => {
  try {
    const givenId = req.params.id;
    const boat = await Boat.findByPk(givenId);
    if (boat) {
      return res.status(200).json({
        success: true,
        result: {
          id: boat.id,
          name: boat.name,
          boattype: boat.boattype,
          status: boat.status,
          tags: boat.tags,
          minP: boat.minP,
          maxP: boat.maxP,
          sports: boat.sports,
        },
      });
    }
    return res.status(404).json({ success: false, error: "boatIdNotFound" });
  } catch (error) {
    console.error("server error: ", error.message);
    return res.status(500).json({ success: false, error: "serverError" });
  }
};

//delete specific boat using given id
const deleteBoatById = async (req: Request, res: Response) => {
  try {
    if (!(res.locals.user.role === "coordinator")) {
      return res
        .status(403)
        .json({ success: false, error: "MustBeCoordinator" });
    }
    const givenId = req.params.id;
    const boatToDelete = await Boat.destroy({
      where: {
        id: givenId,
      },
    });
    if (boatToDelete == 0) {
      return res
        .status(404)
        .json({ success: false, error: "BoatIdDoesNotExist" });
    }
    return res.status(204).json({ success: true });
  } catch (error) {
    console.error("server error: ", error.message);
    return res.status(500).json({ success: false, error: "serverError" });
  }
};

//update boat by given id
const updateBoatById = async (req: Request, res: Response) => {
  try {
    //check authority
    if (!(res.locals.user.role === "coordinator")) {
      return res
        .status(403)
        .json({ success: false, error: "MustBeCoordinator" });
    }

    //get new input
    const input = req.body;

    //return 200 with empty response if no data was given
    if (Object.keys(input).length === 0) {
      return res
        .status(200)
        .json({ success: true, result: {}, message: "noInputFound" });
    }

    //get id
    const givenId = req.params.id;

    //check if boat can be found using givenId
    const foundBoat = await Boat.findByPk(givenId);

    if (!foundBoat) {
      return res.status(404).json({ success: false, error: "boatIdNotFound" });
    }

    //check if new boattype can be found
    if (!(await BoatType.findByPk(input.boattype))) {
      return res
        .status(404)
        .json({ success: false, error: "givenBoatTypeIdNotFound" });
    }

    //check if new given sport-ids can be found
    const newSportsArray = input.sports;
    //check wether each new given id exists or not
    for (let i = 0; i < newSportsArray.length; i++) {
      const found = await Sport.findByPk(newSportsArray[i]);
      if (!found)
        return res
          .status(404)
          .json({ success: false, error: newSportsArray[i] + " notFound" });
    }

    //try to update
    const updatedBoat = await Boat.update(input, {
      where: {
        id: givenId,
      },
      returning: true,
    });

    //return after updating
    const boatDataAfterUpdate = updatedBoat[1][0];
    return res.status(200).json({
      success: true,
      result: {
        id: boatDataAfterUpdate.id,
        name: boatDataAfterUpdate.name,
        boattype: boatDataAfterUpdate.boattype,
        status: boatDataAfterUpdate.status,
        tags: boatDataAfterUpdate.tags,
        minP: boatDataAfterUpdate.minP,
        maxP: boatDataAfterUpdate.maxP,
        sports: boatDataAfterUpdate.sports,
      },
    });
  } catch (error) {
    console.error("server error: ", error.message);
    return res.status(500).json({ success: false, error: "serverError" });
  }
};

const boatControllers = {
  showAllBoatsController,
  showBoatById,
  deleteBoatById,
  createBoat,
  updateBoatById,
};

export default boatControllers;