import { IpcClient as SeekerIpc } from "@autoplex-api/seeker";
import { MovieInfo, MovieTicket } from "@autoplex/database";
import { handleRequest, RouteRegisterFactory, MiddlewareMethod, Status, respond } from "@autoplex/webserver";
import Application from "../../../Application";
import MovieSearch from "../../MovieSearch";
import { auth } from "../middleware/auth";
import { RequestTmdbMovieRequest } from "../requests";
import { convertTicketsToMovies } from "../../../utils";

/**
 * Register API routes
 */
export default function register(factory: RouteRegisterFactory<MiddlewareMethod<void>, Application>, app: Application) {

	factory.prefix("/api", [auth], (factory, app) => {

		/**
		 * Service proxies
		 */
		factory.proxy("/tvdb/artwork", "https://artworks.thetvdb.com/");
		factory.proxy("/tmdb/image", "https://image.tmdb.org/t/p/");

		/**
		 * Search for a movie
		 */
		factory.get("/movie/search", async (request, reply) => {
			let query = <string>(<any>request.query)["query"];
			let year = parseInt((<any>request.query)["year"]) || undefined;
			let results = await app.service<MovieSearch>("Movie Search").search(query, year);
			respond(reply, Status.Ok, results);
		});

		/**
		 * Lookup a movie's details
		 */
		factory.get("/movie/details/:id", async (request, reply) => {
			let id = parseInt((<any>request.params)["id"]);
			if (id.toString() !== (<any>request.params)["id"].trim()) {
				return respond(reply, Status.BadRequest);
			}
			let results = await app.service<MovieSearch>("Movie Search").details(id);
			respond(reply, Status.Ok, results);
		});

		// Movie Request ---------------------------------------------------------------------------

		factory.prefix("/movie/request", [], (factory, app) => {
			/**
			 * Fetch a user's active movie tickets
			 */
			factory.get("/active", async (request, reply) => {
				let user = request.middlewareParams.auth.user;
				let tickets = await user.activeMovieTickets();
				let movies = await convertTicketsToMovies(tickets);
				respond(reply, Status.Ok, movies);
				return reply.send({ status: "Success", data: movies });
			});

			/**
			 * Fetch a movie request
			 */
			factory.get("/:id", async (request, reply) => {
				let id = parseInt((<any>request.params)["id"]);
				let ticket = await MovieTicket.findOne(id);
				if (ticket === undefined) {
					return respond(reply, Status.NotFound);
				}
				let movie = (await convertTicketsToMovies([ticket]))[0];
				respond(reply, Status.Ok, movie);
			});

			/**
			 * Cancel an active request
			 */
			factory.delete("/:id", async (request, reply) => {
				let user = request.middlewareParams.auth.user;
				let id = parseInt((<any>request.params)["id"]);
				let ticket = await MovieTicket.findOne(id, { where: { user: user.id } });
				if (ticket === undefined) {
					return respond(reply, Status.NotFound);
				}
				ticket.isCanceled = true;
				await ticket.save();
				respond(reply, Status.Ok);
			});

			/**
			 * Request a movie to download
			 */
			factory.post("/create/:tmdb_id", handleRequest([RequestTmdbMovieRequest], async (request, reply) => {
				// Verify that the ID has not yet been requested
				let tmdbId = (<any>request.params)["tmdb_id"];
				if (0 != await MovieTicket.count({ where: { tmdbId, isCanceled: false } })) {
					return respond(reply, Status.Conflict);
				}
				let movie = await app.service<MovieSearch>("Movie Search").details(tmdbId);
				if (!movie) {
					return respond(reply, Status.NotFound);
				}
				// Create the movie request ticket
				let user = request.middlewareParams.auth.user;

				let info = new MovieInfo();
				info.originalLanguage = movie.originalLanguage;
				info.originalTitle = movie.originalTitle;
				info.overview = movie.overview;
				info.posterPath = movie.posterPath;
				info.backdropPath = movie.backdropPath;
				info.releaseDate = movie.releaseDate;
				info.runtime = movie.runtime;
				await info.save();

				let ticket = new MovieTicket();
				ticket.tmdbId = movie.tmdbId;
				ticket.imdbId = movie.imdbId;
				ticket.title = movie.title;
				ticket.year = movie.releaseDate ? parseInt(movie.releaseDate.slice(0, 4)) : null;
				ticket.user = user;
				ticket.info = info;
				await ticket.save();

				app.service<SeekerIpc>("Seeker").notifyMovieRequested(ticket.id);
				respond(reply, Status.Ok, { ticketId: ticket.id });
			}));
		});
	});
}
