package server

import (
	"net/http"

	"git.mstar.dev/mstar/goutils/other"
	"git.mstar.dev/mstar/linstrom/storage"
)

func setupLinstromApiRouter() http.Handler {
	router := http.NewServeMux()
	router.Handle("/v1/", http.StripPrefix("/v1", setupLinstromApiV1Router()))
	router.Handle("/s2s/v1/", http.StripPrefix("/s2s/v1", setupLinstromS2SApiV1Router()))

	return router
}

func setupLinstromApiV1Router() http.Handler {
	router := http.NewServeMux()

	// Notes

	// Get a note
	router.HandleFunc("GET /notes/{noteId}", linstromGetNote)
	// Send a new note
	router.HandleFunc("POST /notes", linstromNewNote)
	// Update a note
	router.HandleFunc("PATCH /notes/{noteId}", linstromUpdateNote)
	// Delete a note
	router.HandleFunc("DELETE /notes/{noteId}", linstromDeleteNote)

	// Reactions

	// Get all reactions for a note
	router.HandleFunc("GET /notes/{noteId}/reactions", linstromGetReactions)
	// Send a new reaction to a note
	router.HandleFunc("POST /notes/{noteId}/reactions", linstromAddReaction)
	// Update own reaction on a note
	router.HandleFunc("PATCH /notes/{noteId}/reactions", linstromUpdateReaction)
	// Remove own reaction on a note
	router.HandleFunc("DELETE /notes/{noteId}/reactions", linstromDeleteReaction)

	// Boosts

	// Get all boosters of a note
	router.HandleFunc("GET /notes/{noteId}/boosts", linstromGetBoosts)
	// Boost a note
	router.HandleFunc("POST /notes/{noteId}/boosts", linstromAddBoost)
	// Unboost a note
	router.HandleFunc("DELETE /notes/{noteId}/boosts", linstromRemoveBoost)

	// Quotes

	// Get all quotes of a note
	router.HandleFunc("GET /notes/{noteId}/quotes", linstromGetQuotes)
	// Create a new quote message of a given note
	router.HandleFunc("POST /notes/{noteId}/quotes", linstromAddQuote)

	// Pinning

	// Pin a note to account profile
	router.HandleFunc("POST /notes/{noteId}/pin", linstromPinNote)
	// Unpin a note from account profile
	router.HandleFunc("DELETE /notes/{noteId}/pin", linstromUnpinNote)
	// Reports
	router.HandleFunc("POST /notes/{noteId}/report", linstromReportNote)
	router.HandleFunc("DELETE /notes/{noteId}/report", linstromRetractReportNote)
	// Admin
	router.HandleFunc("POST /notes/{noteId}/admin/cw", linstromForceCWNote)

	// Accounts
	// Creating a new account happens either during fetch of a remote one or during registration with a passkey

	// Get an account
	router.HandleFunc("GET /accounts/{accountId}", linstromGetAccount)
	// Update own account
	// Technically also requires authenticated account to also be owner or correct admin perms,
	// but that's annoying to handle in a general sense. So leaving that to the function
	// though figuring out a nice generic-ish way to handle those checks would be nice too
	router.HandleFunc(
		"PATCH /accounts/{accountId}",
		requireValidSessionMiddleware(linstromUpdateAccount),
	)
	// Delete own account
	// Technically also requires authenticated account to also be owner or correct admin perms,
	// but that's annoying to handle in a general sense. So leaving that to the function
	router.HandleFunc(
		"DELETE /accounts/{accountId}",
		requireValidSessionMiddleware(linstromDeleteAccount),
	)
	// Follow
	// Is logged in following accountId
	router.HandleFunc(
		"GET /accounts/{accountId}/follow/to",
		requireValidSessionMiddleware(linstromIsFollowingToAccount),
	)
	// Is accountId following logged in
	router.HandleFunc(
		"GET /accounts/{accountId}/follow/from",
		requireValidSessionMiddleware(linstromIsFollowingFromAccount),
	)
	// Send follow request to accountId
	router.HandleFunc("POST /accounts/{accountId}/follow", linstromFollowAccount)
	// Undo follow request to accountId
	router.HandleFunc("DELETE /accounts/{accountId}/follow", linstromUnfollowAccount)

	// Block

	// Is logged in account blocking target account
	router.HandleFunc("GET /accounts/{accountId}/block", linstromIsBlockingAccount)
	// Block target account
	router.HandleFunc("POST /accounts/{accountId}/block", linstromBlockAccount)
	// Unblock target account
	router.HandleFunc("DELETE /accounts/{accountId}/block", linstromUnblockAccount)

	// Mute

	// Has logged in account muted target account?
	router.HandleFunc("GET /accounts/{accountId}/mute", linstromIsMutedAccount)
	// Mute target account
	router.HandleFunc("POST /accounts/{accountId}/mute", linstromMuteAccount)
	// Unmute target account
	router.HandleFunc("DELETE /accounts/{accountId}/mute", linstromUnmuteAccount)

	// Report

	// Report a target account
	router.HandleFunc("POST /accounts/{accountId}/reports", linstromReportAccount)
	// Undo report on target account
	router.HandleFunc("DELETE /accounts/{accountId}/reports", linstromRetractReportAccount)

	// Admin

	// Add new role to account
	router.Handle(
		"POST /accounts/{accountId}/admin/roles",
		buildRequirePermissionsMiddleware(
			&storage.Role{CanAssignRoles: other.IntoPointer(true)},
		)(
			http.HandlerFunc(linstromAdminAddRoleAccount),
		),
	)
	// Remove role from account
	router.Handle(
		"DELETE /accounts/{accountId}/admin/roles/{roleName}",
		buildRequirePermissionsMiddleware(&storage.Role{CanAssignRoles: other.IntoPointer(true)})(
			http.HandlerFunc(linstromAdminRemoveRoleAccount),
		),
	)
	// Send a warning to account
	router.HandleFunc("POST /accounts/{accountId}/admin/warn", linstromAdminWarnAccount)

	// Roles

	// Get a role
	router.HandleFunc("GET /roles/{roleId}", linstromGetRole)
	// Create a new role
	router.HandleFunc("POST /roles", linstromCreateRole)
	// Update a role. Builtin roles cannot be edited
	router.HandleFunc("PATCH /roles/{roleId}", linstromUpdateRole)
	// Delete a role. Builtin roles cannot be deleted
	router.HandleFunc("DELETE /roles/{roleId}", linstromDeleteRole)

	// Media metadata

	// Get the metadata for some media
	router.HandleFunc("GET /media/{mediaId}", linstromGetMediaMetadata)
	// Upload new media
	router.HandleFunc("POST /media", linstromNewMediaMetadata)
	// Update the metadata for some media
	router.HandleFunc("PATCH /media/{mediaId}", linstromUpdateMediaMetadata)
	// Delete a media entry
	router.HandleFunc("DELETE /media/{mediaId}", linstromDeleteMediaMetadata)

	// Event streams
	router.HandleFunc("/streams", linstromEventStream)

	return router
}

func setupLinstromS2SApiV1Router() http.Handler {
	router := http.NewServeMux()
	// TODO: Figure out a decent server to server API definition
	router.HandleFunc("/", placeholderEndpoint)
	return router
}
