import { Request, Response } from "express";
import MemberService from "../../../service/club/member/memberService";
import MemberFactory from "../../../factory/admin/club/member/member";
import MembershipService from "../../../service/club/member/membershipService";
import MembershipFactory from "../../../factory/admin/club/member/membership";
import MemberAwardService from "../../../service/club/member/memberAwardService";
import MemberAwardFactory from "../../../factory/admin/club/member/memberAward";
import MemberQualificationService from "../../../service/club/member/memberQualificationService";
import MemberQualificationFactory from "../../../factory/admin/club/member/memberQualification";
import MemberExecutivePositionService from "../../../service/club/member/memberExecutivePositionService";
import MemberExecutivePositionFactory from "../../../factory/admin/club/member/memberExecutivePosition";
import CommunicationService from "../../../service/club/member/communicationService";
import CommunicationFactory from "../../../factory/admin/club/member/communication";
import {
  CreateMemberCommand,
  DeleteMemberCommand,
  UpdateMemberCommand,
  UpdateMemberNewsletterCommand,
} from "../../../command/club/member/memberCommand";
import MemberCommandHandler from "../../../command/club/member/memberCommandHandler";
import {
  CreateMembershipCommand,
  DeleteMembershipCommand,
  UpdateMembershipCommand,
} from "../../../command/club/member/membershipCommand";
import MembershipCommandHandler from "../../../command/club/member/membershipCommandHandler";
import {
  CreateMemberAwardCommand,
  DeleteMemberAwardCommand,
  UpdateMemberAwardCommand,
} from "../../../command/club/member/memberAwardCommand";
import MemberAwardCommandHandler from "../../../command/club/member/memberAwardCommandHandler";
import {
  CreateMemberExecutivePositionCommand,
  DeleteMemberExecutivePositionCommand,
  UpdateMemberExecutivePositionCommand,
} from "../../../command/club/member/memberExecutivePositionCommand";
import MemberExecutivePositionCommandHandler from "../../../command/club/member/memberExecutivePositionCommandHandler";
import {
  CreateMemberQualificationCommand,
  DeleteMemberQualificationCommand,
  UpdateMemberQualificationCommand,
} from "../../../command/club/member/memberQualificationCommand";
import MemberQualificationCommandHandler from "../../../command/club/member/memberQualificationCommandHandler";
import {
  CreateCommunicationCommand,
  DeleteCommunicationCommand,
  UpdateCommunicationCommand,
} from "../../../command/club/member/communicationCommand";
import CommunicationCommandHandler from "../../../command/club/member/communicationCommandHandler";
import { PdfExport } from "../../../helpers/pdfExport";
import { PermissionModule } from "../../../type/permissionTypes";

/**
 * @description get all members
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getAllMembers(req: Request, res: Response): Promise<any> {
  let offset = parseInt((req.query.offset as string) ?? "0");
  let count = parseInt((req.query.count as string) ?? "25");
  let search = (req.query.search as string) ?? "";
  let noLimit = req.query.noLimit === "true";
  let ids = ((req.query.ids ?? "") as string)
    .split(",")
    .filter((i) => i)
    .map((i) => parseInt(i));

  let [members, total] = await MemberService.getAll({ offset, count, search, noLimit, ids });

  res.json({
    members: MemberFactory.mapToBase(members),
    total: total,
    offset: offset,
    count: count,
  });
}

/**
 * @description get member by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getMemberById(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.id);
  let member = await MemberService.getById(memberId);

  res.json(MemberFactory.mapToSingle(member));
}

/**
 * @description get member statistics by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getMemberStatisticsById(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.id);
  let member = await MemberService.getStatisticsById(memberId);

  res.json(MemberFactory.mapToMemberStatistic(member));
}

/**
 * @description get memberships by member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getMembershipsByMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  let memberships = await MembershipService.getAll(memberId);

  res.json(MembershipFactory.mapToBase(memberships));
}

/**
 * @description get member statistics by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getMembershipStatisticsById(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  let member = await MembershipService.getStatisticsById(memberId);

  res.json(MembershipFactory.mapToBaseStatistics(member));
}

/**
 * @description get membership by member and record
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getMembershipByMemberAndRecord(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.id);
  let membership = await MembershipService.getById(memberId, recordId);

  res.json(MembershipFactory.mapToSingle(membership));
}

/**
 * @description get awards by member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getAwardsByMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  let awards = await MemberAwardService.getAll(memberId);

  res.json(MemberAwardFactory.mapToBase(awards));
}

/**
 * @description get award by member and record
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getAwardByMemberAndRecord(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.id);
  let award = await MemberAwardService.getById(memberId, recordId);

  res.json(MemberAwardFactory.mapToSingle(award));
}

/**
 * @description get qualifications by member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getQualificationsByMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  let qualifications = await MemberQualificationService.getAll(memberId);

  res.json(MemberQualificationFactory.mapToBase(qualifications));
}

/**
 * @description get qualification by member and record
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getQualificationByMemberAndRecord(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.id);
  let qualification = await MemberQualificationService.getById(memberId, recordId);

  res.json(MemberQualificationFactory.mapToSingle(qualification));
}

/**
 * @description get executive positions by member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getExecutivePositionsByMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  let positions = await MemberExecutivePositionService.getAll(memberId);

  res.json(MemberExecutivePositionFactory.mapToBase(positions));
}

/**
 * @description get executive position by member and record
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getExecutivePositionByMemberAndRecord(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.id);
  let position = await MemberExecutivePositionService.getById(memberId, recordId);

  res.json(MemberExecutivePositionFactory.mapToSingle(position));
}

/**
 * @description get communications by member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getCommunicationsByMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  let communications = await CommunicationService.getAll(memberId);

  res.json(CommunicationFactory.mapToBase(communications));
}

/**
 * @description get communication by member and record
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function getCommunicationByMemberAndRecord(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.id);
  let communication = await CommunicationService.getById(memberId, recordId);

  res.json(CommunicationFactory.mapToSingle(communication));
}

/**
 * @description create member printout list
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function createMemberPrintoutList(req: Request, res: Response): Promise<any> {
  let members = await MemberService.getByRunningMembership();

  let pdf = await PdfExport.renderFile({
    title: "Mitgliederliste",
    template: "member.list",
    saveToDisk: false,
    data: {
      member: members,
    },
  });

  let pdfbuffer = Buffer.from(pdf);

  res.setHeader("Content-Type", "application/pdf");
  res.setHeader("Content-Length", pdfbuffer.byteLength);
  res.setHeader("Content-Disposition", "inline; filename=preview.pdf");

  res.send(pdfbuffer);
}

/**
 * @description create member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function createMember(req: Request, res: Response): Promise<any> {
  const salutation = req.body.salutation;
  const firstname = req.body.firstname;
  const lastname = req.body.lastname;
  const nameaffix = req.body.nameaffix;
  const birthdate = req.body.birthdate;
  const internalId = req.body.internalId;

  let createMember: CreateMemberCommand = {
    salutation,
    firstname,
    lastname,
    nameaffix,
    birthdate,
    internalId,
  };
  let memberId = await MemberCommandHandler.create(createMember);

  res.status(200).send(memberId);
}

/**
 * @description add memberships to member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function addMembershipToMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const start = req.body.start;
  const statusId = req.body.statusId;

  let createMembership: CreateMembershipCommand = {
    start,
    memberId,
    statusId,
  };
  await MembershipCommandHandler.create(createMembership);

  res.sendStatus(204);
}

/**
 * @description add awards to member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function addAwardToMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const given = req.body.given;
  const note = req.body.note;
  const date = req.body.date;
  const awardId = req.body.awardId;

  let createMemberAward: CreateMemberAwardCommand = {
    given,
    note,
    date,
    memberId,
    awardId,
  };
  await MemberAwardCommandHandler.create(createMemberAward);

  res.sendStatus(204);
}

/**
 * @description add qualifications to member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function addQualificationToMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const note = req.body.note;
  const start = req.body.start;
  const qualificationId = req.body.qualificationId;

  let createMemberQualification: CreateMemberQualificationCommand = {
    note,
    start,
    memberId,
    qualificationId,
  };
  await MemberQualificationCommandHandler.create(createMemberQualification);

  res.sendStatus(204);
}

/**
 * @description add executive positions to member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function addExecutivePositionToMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const note = req.body.note;
  const start = req.body.start;
  const end = req.body.end || null;
  const executivePositionId = req.body.executivePositionId;

  let createMemberExecutivePosition: CreateMemberExecutivePositionCommand = {
    note,
    start,
    end,
    memberId,
    executivePositionId,
  };
  await MemberExecutivePositionCommandHandler.create(createMemberExecutivePosition);

  res.sendStatus(204);
}

/**
 * @description add communications to member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function addCommunicationToMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const preferred = req.body.preferred;
  const isSMSAlarming = req.body.isSMSAlarming;
  const mobile = req.body.mobile;
  const email = req.body.email;
  const postalCode = req.body.postalCode;
  const city = req.body.city;
  const street = req.body.street;
  const streetNumber = req.body.streetNumber;
  const streetNumberAddition = req.body.streetNumberAddition;
  const typeId = req.body.typeId;
  const isNewsletterMain = req.body.isNewsletterMain;

  let createCommunication: CreateCommunicationCommand = {
    preferred,
    isSMSAlarming,
    mobile,
    email,
    postalCode,
    city,
    street,
    streetNumber,
    streetNumberAddition,
    memberId,
    typeId,
  };
  let id = await CommunicationCommandHandler.create(createCommunication);

  if (isNewsletterMain) {
    let updateNewsletter: UpdateMemberNewsletterCommand = {
      id: memberId,
      communicationId: id,
    };
    await MemberCommandHandler.updateNewsletter(updateNewsletter);
  }

  res.sendStatus(204);
}

/**
 * @description update member by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function updateMemberById(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.id);
  const salutation = req.body.salutation;
  const firstname = req.body.firstname;
  const lastname = req.body.lastname;
  const nameaffix = req.body.nameaffix;
  const birthdate = req.body.birthdate;
  const internalId = req.body.internalId;

  let updateMember: UpdateMemberCommand = {
    id: memberId,
    salutation,
    firstname,
    lastname,
    nameaffix,
    birthdate,
    internalId,
  };
  await MemberCommandHandler.update(updateMember);

  res.sendStatus(204);
}

/**
 * @description update membership of member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function updateMembershipOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);
  const start = req.body.start;
  const end = req.body.end || null;
  const terminationReason = req.body.terminationReason;
  const statusId = req.body.statusId;

  let updateMembership: UpdateMembershipCommand = {
    id: recordId,
    start,
    end,
    terminationReason,
    memberId,
    statusId,
  };
  await MembershipCommandHandler.update(updateMembership);

  res.sendStatus(204);
}

/**
 * @description update award of member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function updateAwardOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);
  const given = req.body.given;
  const note = req.body.note;
  const date = req.body.date;
  const awardId = req.body.awardId;

  let updateMemberAward: UpdateMemberAwardCommand = {
    id: recordId,
    given,
    note,
    date,
    memberId,
    awardId,
  };
  await MemberAwardCommandHandler.update(updateMemberAward);

  res.sendStatus(204);
}

/**
 * @description update qualification of member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function updateQualificationOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);
  const note = req.body.note;
  const start = req.body.start;
  const end = req.body.end || null;
  const terminationReason = req.body.terminationReason;
  const qualificationId = req.body.qualificationId;

  let updateMemberQualification: UpdateMemberQualificationCommand = {
    id: recordId,
    note,
    start,
    end,
    terminationReason,
    memberId,
    qualificationId,
  };
  await MemberQualificationCommandHandler.update(updateMemberQualification);

  res.sendStatus(204);
}

/**
 * @description update executive position of member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function updateExecutivePositionOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);
  const note = req.body.note;
  const start = req.body.start;
  const end = req.body.end || null;
  const executivePositionId = req.body.executivePositionId;

  let updateMemberExecutivePosition: UpdateMemberExecutivePositionCommand = {
    id: recordId,
    note,
    start,
    end,
    memberId,
    executivePositionId,
  };
  await MemberExecutivePositionCommandHandler.update(updateMemberExecutivePosition);

  res.sendStatus(204);
}

/**
 * @description update communication of member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function updateCommunicationOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);
  const preferred = req.body.preferred;
  const isSMSAlarming = req.body.isSMSAlarming;
  const mobile = req.body.mobile;
  const email = req.body.email;
  const postalCode = req.body.postalCode;
  const city = req.body.city;
  const street = req.body.street;
  const streetNumber = req.body.streetNumber;
  const streetNumberAddition = req.body.streetNumberAddition;
  const isNewsletterMain = req.body.isNewsletterMain;

  let updateCommunication: UpdateCommunicationCommand = {
    id: recordId,
    preferred,
    isSMSAlarming,
    mobile,
    email,
    postalCode,
    city,
    street,
    streetNumber,
    streetNumberAddition,
    memberId,
  };
  await CommunicationCommandHandler.update(updateCommunication);

  let currentUserNewsletterMain = await MemberService.getNewsletterById(memberId);

  if (isNewsletterMain) {
    let updateNewsletter: UpdateMemberNewsletterCommand = {
      id: memberId,
      communicationId: recordId,
    };
    await MemberCommandHandler.updateNewsletter(updateNewsletter);
  } else if (currentUserNewsletterMain.sendNewsletter?.id == recordId) {
    await MemberCommandHandler.unsetNewsletter(memberId);
  }

  res.sendStatus(204);
}

/**
 * @description delete member by id
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function deleteMemberById(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.id);

  let deleteMember: DeleteMemberCommand = {
    id: memberId,
  };
  await MemberCommandHandler.delete(deleteMember);

  res.sendStatus(204);
}

/**
 * @description delete membership from member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function deleteMembershipOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);

  let deleteMembership: DeleteMembershipCommand = {
    id: recordId,
    memberId,
  };
  await MembershipCommandHandler.delete(deleteMembership);

  res.sendStatus(204);
}

/**
 * @description delete award from member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function deleteAwardOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);

  let deleteMemberAward: DeleteMemberAwardCommand = {
    id: recordId,
    memberId,
  };
  await MemberAwardCommandHandler.delete(deleteMemberAward);

  res.sendStatus(204);
}

/**
 * @description delete qualification from member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function deleteQualificationOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);

  let deleteMemberQualification: DeleteMemberQualificationCommand = {
    id: recordId,
    memberId,
  };
  await MemberQualificationCommandHandler.delete(deleteMemberQualification);

  res.sendStatus(204);
}

/**
 * @description delete executive position from member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function deleteExecutivePositionOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);

  let deleteMemberExecutivePosition: DeleteMemberExecutivePositionCommand = {
    id: recordId,
    memberId,
  };
  await MemberExecutivePositionCommandHandler.delete(deleteMemberExecutivePosition);

  res.sendStatus(204);
}

/**
 * @description delete communication from member
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function deleteCommunicationOfMember(req: Request, res: Response): Promise<any> {
  const memberId = parseInt(req.params.memberId);
  const recordId = parseInt(req.params.recordId);

  let deleteCommunication: DeleteCommunicationCommand = {
    id: recordId,
    memberId,
  };
  await CommunicationCommandHandler.delete(deleteCommunication);

  res.sendStatus(204);
}