// src/server/features/auth/auth.routes.ts
// HTTP handlers for authentication routes

import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { FastifyInstance } from 'fastify';
import { z } from 'zod';
import {
  loginSchema,
  registerSchema,
  loginResponseSchema,
  registerResponseSchema,
  errorResponseSchema,
  logoutResponseSchema,
} from './auth.schema';
import { login, register, guestLogin } from './auth.service';
import { AuthorizationError, ACCOUNT_DISABLED_ERROR_CODE, isAccountAccessAllowed } from '@serverShared/lib/auth';
import { db } from '@serverShared/db/client';
import { employees } from '../personnel/db/employees.table';
import { eq } from 'drizzle-orm';
import { getAuthCookieOptions, getClearCookieOptions } from '@serverShared/lib/env';

export const authRoutes = async (fastify: FastifyInstance) => {
  const server = fastify.withTypeProvider<ZodTypeProvider>();

  // POST /login - Authenticate user and set JWT token in HttpOnly cookie
  server.post('/login', {
    schema: {
      body: loginSchema,
      response: {
        200: loginResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request: any, reply: any) => {
    const { username, password } = request.body;

    const result = await login({ username, password });

    // Get fresh user data from database to check account access
    const freshUserData = await db
      .select({
        id: employees.id,
        isFired: employees.isFired,
        createdAt: employees.createdAt,
        archivedAt: employees.archivedAt,
      })
      .from(employees)
      .where(eq(employees.id, result.user.id))
      .limit(1);

    if (!freshUserData || freshUserData.length === 0) {
      throw new AuthorizationError('Пользователь не найден', 403, ACCOUNT_DISABLED_ERROR_CODE);
    }

    const { isFired, createdAt, archivedAt } = freshUserData[0];

    // Check if account access is allowed
    // isFired may be null from DB, treat null as false (not fired)
    const accessAllowed = isAccountAccessAllowed({
      isFired: isFired ?? false,
      createdAt,
      archivedAt,
    });

    if (!accessAllowed) {
      // Determine appropriate error message based on the reason
      const { dayjs } = await import('@serverShared/lib/dayjs'); 
      const mskNow = dayjs().tz('Europe/Moscow');
      const isFutureHire = mskNow.isBefore(dayjs.utc(createdAt).tz('Europe/Moscow').startOf('day'));
      const errorMessage = isFutureHire
        ? 'Учетная запись еще не активирована'
        : 'Срок действия учетной записи истек';

      throw new AuthorizationError(errorMessage, 403, ACCOUNT_DISABLED_ERROR_CODE);
    }

    // Generate JWT token
    const token = fastify.jwt.sign({
      id: result.user.id,
      username: result.user.username,
      role: result.user.role,
    });

    reply.setCookie('auth_token', token, getAuthCookieOptions());

    await db
      .update(employees)
      .set({ lastActivityAt: new Date() })
      .where(eq(employees.id, result.user.id));

    reply.code(200).send({
      success: true,
      data: {
        user: {
          ...result.user,
          employeeId: result.user.id,
        },
      },
    });
  });

  // POST /guest - Authenticate guest user via system VIEWER account
  server.post('/guest', {
    schema: {
      response: {
        200: loginResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (_request: any, reply: any) => {
    const result = await guestLogin();

    // Generate JWT token
    const token = fastify.jwt.sign({
      id: result.user.id,
      username: result.user.username,
      role: result.user.role,
    });

    reply.setCookie('auth_token', token, getAuthCookieOptions());

    await db
      .update(employees)
      .set({ lastActivityAt: new Date() })
      .where(eq(employees.id, result.user.id));

    reply.code(200).send({
      success: true,
      data: {
        user: {
          ...result.user,
          employeeId: result.user.id,
        },
      },
    });
   });

  // POST /register - Register new user and employee
  server.post('/register', {
    schema: {
      body: registerSchema,
      response: {
        200: registerResponseSchema,
        400: errorResponseSchema,
      },
    },
  }, async (request: any, reply: any) => {
    const { username, password, email, name, position, phone } = request.body;

    const result = await register({ username, password, email, name, position, phone });
    reply.code(200).send({
      success: true,
      data: {
        user: {
          ...result,
          employeeId: result.id, // Map id to employeeId for frontend compatibility
        },
      },
    });
  });

  // POST /logout - Clear auth cookie
  server.post('/logout', {
    schema: {
      response: {
        200: logoutResponseSchema,
      },
    },
  }, async (request: any, reply: any) => {
    reply.setCookie('auth_token', '', getClearCookieOptions());

    reply.code(200).send({ success: true });
  });

  server.post('/heartbeat', {
    schema: {
      response: {
        200: z.object({ success: z.boolean() }),
      },
    },
  }, async (request: any, reply: any) => {
    try {
      const user = await request.jwtVerify({ onlyCookie: true }).catch(() => null);
      if (!user || !user.id) {
        return reply.code(200).send({ success: true });
      }

      await db
        .update(employees)
        .set({ lastActivityAt: new Date() })
        .where(eq(employees.id, user.id));

      return reply.code(200).send({ success: true });
    } catch {
      return reply.code(200).send({ success: true });
    }
  });
};
