import { setUserMetadata, superTokensFunctionMiddleware, getSessionContext } from "@/utils/supertokens";
import { createServerFn } from "@tanstack/react-start";
import { isRedirect } from "@tanstack/react-router";
import { Player, playerInputSchema, playerUpdateSchema, PlayerStats } from "@/features/players/types";
import { Match } from "@/features/matches/types";
import { z } from "zod";
import { Logger } from "@/lib/logger";
import { getRequest } from "@tanstack/react-start/server";
import { toServerResult } from "@/lib/tanstack-query/utils/to-server-result";
import { serverFnLoggingMiddleware } from "@/utils/activities";

const logger = new Logger('Players');

export const fetchMe = createServerFn()
  .handler(async () =>
    toServerResult(async () => {
      const request = getRequest();
      const { parseAcceptLanguage } = await import("@/lib/i18n");
      const detectedLocale = parseAcceptLanguage(
        request.headers.get("accept-language")
      );

      try {
        const context = await getSessionContext(request);

        return {
          user: context.player || undefined,
          roles: context.roles,
          metadata: {
            ...context.metadata,
            locale: context.metadata?.locale ?? detectedLocale,
          },
          phone: context.phone
        };
      } catch (error: any) {
        if (isRedirect(error) || error instanceof Response) throw error;

        return { user: undefined, roles: [], metadata: { locale: detectedLocale }, phone: undefined };
      }
    })
  );

export const getPlayer = createServerFn()
  .validator(z.string())
  .middleware([superTokensFunctionMiddleware])
  .handler(async ({ data }) =>
    toServerResult<Player>(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.getPlayer(data);
    })
  );

export const updatePlayer = createServerFn()
  .validator(playerUpdateSchema)
  .middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware])
  .handler(async ({ context, data }) =>
    toServerResult(async () => {
      const userAuthId = context.userAuthId;
      if (!userAuthId) return;

      const { pbAdmin } = await import("@/lib/pocketbase/client");

      const existing = await pbAdmin.getPlayerByAuthId(userAuthId);
      if (!existing) return;

      const updatedPlayer = await pbAdmin.updatePlayer(
        existing.id!,
        {
          first_name: data.first_name,
          last_name: data.last_name
        }
      );

      logger.info('Updated player name', updatedPlayer);

      await setUserMetadata({ data: { first_name: data.first_name, last_name: data.last_name } });

      const { emitServerEvent } = await import("@/lib/events/emitter");
      emitServerEvent({ type: "player", playerId: existing.id! });

      return updatedPlayer;
    })
  );

export const createPlayer = createServerFn()
  .validator(playerInputSchema)
  .middleware([superTokensFunctionMiddleware])
  .handler(async ({ context, data }) =>
    toServerResult(async () => {
      const userAuthId = context.userAuthId;
      if (!userAuthId) return;

      const { pbAdmin } = await import("@/lib/pocketbase/client");

      const existing = await pbAdmin.getPlayerByAuthId(userAuthId);
      if (existing) return;

      logger.info('Creating player', data, userAuthId);

      const newPlayer = await pbAdmin.createPlayer({
        auth_id: userAuthId,
        first_name: data.first_name,
        last_name: data.last_name
      });

      await setUserMetadata({ data: { first_name: data.first_name, last_name: data.last_name, player_id: newPlayer?.id?.toString() } });
      logger.info('Created player', newPlayer);

      if (newPlayer?.id) {
        const { emitServerEvent } = await import("@/lib/events/emitter");
        emitServerEvent({ type: "player", playerId: newPlayer.id });
      }

      return newPlayer;
    })
  );

export const associatePlayer = createServerFn()
  .validator(z.string())
  .middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware])
  .handler(async ({ context, data }) =>
    toServerResult(async () => {
      const userAuthId = context.userAuthId;
      if (!userAuthId) return;

      const { pbAdmin } = await import("@/lib/pocketbase/client");

      const p = await pbAdmin.getPlayer(data);

      await pbAdmin.updatePlayer(data, {
        auth_id: userAuthId
      });

      await setUserMetadata({ data: {
        player_id: data,
        first_name: p?.first_name,
        last_name: p?.last_name
      }});

      const player = await pbAdmin.getPlayer(data);
      logger.info('Associated player', player);

      const { emitServerEvent } = await import("@/lib/events/emitter");
      emitServerEvent({ type: "player", playerId: data });

      return player;
    })
  );

export const listPlayers = createServerFn()
  .middleware([superTokensFunctionMiddleware])
  .handler(async () =>
    toServerResult(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.listPlayers();
    })
  );

export const getUnassociatedPlayers = createServerFn()
  .middleware([superTokensFunctionMiddleware])
  .handler(async () =>
    toServerResult(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.getUnassociatedPlayers();
    })
  );

export const getPlayerStats = createServerFn()
  .validator(z.object({
    playerId: z.string(),
    viewType: z.enum(['all', 'mainline', 'regional']).optional()
  }))
  .middleware([superTokensFunctionMiddleware])
  .handler(async ({ data }) =>
    toServerResult<PlayerStats>(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.getPlayerStats(data.playerId, data.viewType);
    })
  );

export const getAllPlayerStats = createServerFn()
  .validator(z.enum(['all', 'mainline', 'regional']).optional())
  .middleware([superTokensFunctionMiddleware])
  .handler(async ({ data }) =>
    toServerResult<PlayerStats[]>(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.getAllPlayerStats(data);
    })
  );

export const getPlayerMatches = createServerFn()
  .validator(z.string())
  .middleware([superTokensFunctionMiddleware])
  .handler(async ({ data }) =>
    toServerResult<Match[]>(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.getPlayerMatches(data);
    })
  );

export const getUnenrolledPlayers = createServerFn()
  .validator(z.string())
  .middleware([superTokensFunctionMiddleware])
  .handler(async ({ data: tournamentId }) =>
    toServerResult(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.getUnenrolledPlayers(tournamentId);
    })
  );

export const getPlayersActivity = createServerFn()
  .middleware([superTokensFunctionMiddleware])
  .handler(async () =>
    toServerResult<Player[]>(async () => {
      const { pbAdmin } = await import("@/lib/pocketbase/client");
      return await pbAdmin.getPlayersActivity();
    })
  );
