import { z } from "zod";

import { AuthenticationError } from "../../entities/errors/auth";
import { cookieSchema } from "../../entities/models/cookie";
import { sessionSchema } from "../../entities/models/session";
import type { IUsersRepository } from "../repositories/users.repository.interface";
import type { IAuthenticationService } from "../services/authentication.service.interface";

// ── Input ────────────────────────────────────────────────────────────────
export const signInInputSchema = z
  .object({
    username: z.string().min(3).max(31),
    password: z.string().min(6).max(255),
  })
  .strict();
export type SignInInput = z.infer<typeof signInInputSchema>;

// ── Output ───────────────────────────────────────────────────────────────
export const signInOutputSchema = z.object({
  session: sessionSchema,
  cookie: cookieSchema,
});
export type SignInOutput = z.infer<typeof signInOutputSchema>;

// ── Use case ─────────────────────────────────────────────────────────────
export type ISignInUseCase = ReturnType<typeof signInUseCase>;

export const signInUseCase =
  (usersRepository: IUsersRepository, authenticationService: IAuthenticationService) =>
  async (input: SignInInput): Promise<SignInOutput> => {
    const existingUser = await usersRepository.getUserByUsername(input.username);
    if (!existingUser) {
      throw new AuthenticationError("User does not exist");
    }
    const validPassword = await authenticationService.verifyPassword(
      existingUser.passwordHash,
      input.password,
    );
    if (!validPassword) {
      throw new AuthenticationError("Incorrect username or password");
    }
    const result = await authenticationService.createSession(existingUser);
    return signInOutputSchema.parse(result);
  };
