import { ApiValidationError } from "../../Models/Server.Error.model";
import { Body, Controller, Middlewares, Post, Response, Route, SuccessResponse } from "tsoa";
import { authenticateMiddleware } from "../../middleware/authentication";
import {
    AppointmentAdminByClientView,
    AppointmentAdminByDateView,
    CreateAppointmentParams,
    DeleteAppointmentParams,
    FindAppointmentsParams,
    FindAppointmentSchedulesParams,
    IAppointment,
    UpdateAppointmentParams, MoveAppointmentParams, ChangeServiceParams,
    FindAppointmentsByUserParams,
    FindAppointmentsByCollaboratorParams,
    SendAppointmentNotificationParams,
    GetAppointmentEventParams,
    AppointmentEventByClient,
    ApplyAppointmentDiscountParams,
    DeleteAppointmentDiscountParams,
    SendWapSystemNotificationParams,
    GetAvailableDatesParams,
    GetAvailableDatesResult,
    FindAppointmentsByUserPaginatedParams,
    FindAppointmentsByCollaboratorPaginatedParams,
    PaginatedAppointmentEventByClientResult,
} from "../../Models/Appointments/Appointments.Interface";
import { AppointmentService } from "./Appointments.Service";
import { ApiVoidResult } from "../../Models/Api.VoidResult.type";
import { TextObjectFilterResult } from "../../Models/TextObjectFilter.model";
import { rateLimiter } from "../../middleware/ratelimiter";

@Route("appointments/create")
@Middlewares(authenticateMiddleware)
export class CreateAppointmentController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El empleado fue creado con exito")
    @Post()
    public async createAppointment(
        @Body() requestBody: CreateAppointmentParams
    ): Promise<IAppointment | ApiValidationError> {
        try {
            const client = await new AppointmentService().createAppointment(requestBody);
            this.setStatus(200);
            return client;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/update")
@Middlewares(authenticateMiddleware)
export class UpdateAppointmentController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El empleado fue creado con exito")
    @Post()
    public async updateAppointment(
        @Body() requestBody: UpdateAppointmentParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().updateAppointment(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/delete")
@Middlewares(authenticateMiddleware)
export class DeleteAppointmentController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El turno fue cancelado con exito")
    @Post()
    public async deleteAppointment(
        @Body() requestBody: DeleteAppointmentParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().deleteAppointment(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/find-admin-by-date")
@Middlewares(authenticateMiddleware)
export class FindAppointmentAdminByDateController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El empleado fue creado con exito")
    @Post()
    public async findAppointmentAdminByDate(
        @Body() requestBody: FindAppointmentsParams
    ): Promise<AppointmentAdminByDateView | ApiValidationError> {
        try {
            const appointments = await new AppointmentService().findAppointmentsAdminByDate(
                requestBody
            );
            this.setStatus(200);
            return appointments;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/get-event")
@Middlewares(authenticateMiddleware)
export class GetAppointmentEventController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async getAppointmentEvent(
        @Body() requestBody: GetAppointmentEventParams
    ): Promise<AppointmentEventByClient | ApiValidationError> {
        try {
            const appointment = await new AppointmentService().getAppointmentEvent(requestBody);
            this.setStatus(200);
            return appointment;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/find-admin-by-client")
@Middlewares(authenticateMiddleware)
export class FindAppointmentAdminByClientController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El empleado fue creado con exito")
    @Post()
    public async findAppointmentAdminByClient(
        @Body() requestBody: FindAppointmentsParams
    ): Promise<AppointmentAdminByClientView | ApiValidationError> {
        try {
            const appointments = await new AppointmentService().findAppointmentsAdminByClient(
                requestBody
            );
            this.setStatus(200);
            return appointments;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/find-by-user")
@Middlewares(authenticateMiddleware)
export class FindAppointmentByUserController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El empleado fue creado con exito")
    @Post()
    public async findAppointmentByUser(
        @Body() requestBody: FindAppointmentsByUserParams
    ): Promise<AppointmentAdminByClientView | ApiValidationError> {
        try {
            const appointments = await new AppointmentService().findAppointmentsByUser(requestBody);
            this.setStatus(200);
            return appointments;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/find-by-collaborator")
@Middlewares(authenticateMiddleware)
export class FindAppointmentByCollaboratorController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Busqueda completada con exito")
    @Post()
    public async findAppointmentByCollaborator(
        @Body() requestBody: FindAppointmentsByCollaboratorParams
    ): Promise<AppointmentAdminByClientView | ApiValidationError> {
        try {
            const appointments = await new AppointmentService().findAppointmentsByCollaborator(requestBody);
            this.setStatus(200);
            return appointments;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/find-by-user-paginated")
@Middlewares(authenticateMiddleware)
export class FindAppointmentByUserPaginatedController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Busqueda completada con exito")
    @Post()
    public async findAppointmentByUserPaginated(
        @Body() requestBody: FindAppointmentsByUserPaginatedParams
    ): Promise<PaginatedAppointmentEventByClientResult | ApiValidationError> {
        try {
            const appointments = await new AppointmentService().findAppointmentsByUserPaginated(requestBody);
            this.setStatus(200);
            return appointments;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/find-by-collaborator-paginated")
@Middlewares(authenticateMiddleware)
export class FindAppointmentByCollaboratorPaginatedController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Busqueda completada con exito")
    @Post()
    public async findAppointmentByCollaboratorPaginated(
        @Body() requestBody: FindAppointmentsByCollaboratorPaginatedParams
    ): Promise<PaginatedAppointmentEventByClientResult | ApiValidationError> {
        try {
            const appointments = await new AppointmentService().findAppointmentsByCollaboratorPaginated(requestBody);
            this.setStatus(200);
            return appointments;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/get-schedules")
export class GetSchedulesController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async findSchedules(
        @Body() requestBody: FindAppointmentSchedulesParams
    ): Promise<TextObjectFilterResult[] | ApiValidationError> {
        try {
            const schedules = await new AppointmentService().getSchedules(requestBody);
            this.setStatus(200);
            return schedules;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/send-wap-notification")
@Middlewares(rateLimiter)
export class SendWapNotificationContrnoller extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async findSchedules(
        @Body() requestBody: SendAppointmentNotificationParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().sendWapNotification(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/send-wap-sys-notification")
@Middlewares(rateLimiter)
export class SendWapSystemNotificationContrnoller extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async sendWapSystemNtofication(
        @Body() requestBody: SendWapSystemNotificationParams
    ): Promise<ApiVoidResult> {
        try {
            await new AppointmentService().sendWapSystemNotification(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            return {
                message: `${e}`,
                success: false,
            };
        }
    }
}

@Route("appointments/send-email-notification")
@Middlewares(rateLimiter)
export class SendEmailNotificationContrnoller extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async findSchedules(
        @Body() requestBody: SendAppointmentNotificationParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().sendEmailNotification(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/apply-discount")
@Middlewares(authenticateMiddleware)
export class ApplyAppointmentDiscountContrnoller extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async applyAppointmentDiscount(
        @Body() requestBody: ApplyAppointmentDiscountParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().applyDiscount(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/delete-discount")
@Middlewares(authenticateMiddleware)
export class DeleteAppointmentDiscountContrnoller extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async deleteAppointmentDiscount(
        @Body() requestBody: DeleteAppointmentDiscountParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().deleteDiscount(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/get-available-dates")
export class GetAvailableDatesController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "Done")
    @Post()
    public async getAvailableDates(
        @Body() requestBody: GetAvailableDatesParams
    ): Promise<GetAvailableDatesResult | ApiValidationError> {
        try {
            const schedules = await new AppointmentService().getAvailableDates(requestBody);
            this.setStatus(200);
            return schedules;
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/move-appointment-force")
@Middlewares(authenticateMiddleware)
export class MoveAppointmentForceController extends Controller {
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El turno fue movido con exito")
    @Post()
    public async moveAppointmentForce(
        @Body() requestBody: MoveAppointmentParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().moveAppointmentForce(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}

@Route("appointments/change-service-force")
@Middlewares(authenticateMiddleware)
export class ChangeServiceForceController extends Controller {
    /**
     * @summary Permite cambiar el servicio de un turno sin validar horarios (force).
     */
    @Response<ApiValidationError>(500, "Ha ocurrido un error")
    @SuccessResponse(200, "El servicio del turno fue cambiado con exito")
    @Post()
    public async changeServiceForce(
        @Body() requestBody: ChangeServiceParams
    ): Promise<ApiVoidResult | ApiValidationError> {
        try {
            await new AppointmentService().changeServiceForce(requestBody);
            this.setStatus(200);
            return {
                message: "Done",
                success: true,
            };
        } catch (e) {
            const errorOccurred: Error = e as Error; console.error("GET EVENT ERROR:", errorOccurred);
            this.setStatus(500);
            return new ApiValidationError(500, errorOccurred.message);
        }
    }
}
