// src/server/features/system/system.routes.ts
// HTTP handlers for system management routes

import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { FastifyInstance } from 'fastify';
import { z } from 'zod';
import {
  updateLogConfigBodySchema,
  errorResponseSchema,
  getPermissionsResponseSchema,
  getMyPermissionsResponseSchema,
  getModulesResponseSchema,
  bulkUpdatePermissionsSchema,
  bulkUpdateModulesSchema,
  getRoleColorsResponseSchema,
  roleParamSchema,
  updateRoleColorsBodySchema,
  bulkSessionPoliciesBodySchema,
  getSessionPoliciesResponseSchema,
  sessionPolicySchema,
} from './system.schema';
import { loggerService } from '@serverShared/lib/logger';
import { requireAuth } from '@serverShared/lib/auth';
import {
  getAllRolePermissions,
  getRolePermissions,
  bulkUpdateRolePermissions,
  getAllSystemModules,
  bulkUpdateSystemModules,
  getAllRoleColors,
  upsertRoleColors,
  getAllRoleSessionPolicies,
  bulkUpdateRoleSessionPolicies,
  getSessionPolicyForRole,
} from './system.service';
import { clearPermissionsCache } from '@serverShared/plugins/rbac';
import { USER_ROLES } from '@shared/constants/roles';

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

  // GET /logs
  server.get('/logs', {
    preHandler: requireAuth(),
    schema: {
      // REMOVED "response" schema to prevent Fastify from stripping our data
      // We trust the service to return the correct shape
      response: {
        200: z.any(), // Allow any response type for success case
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    // Send RAW config object (matches Frontend expectation)
    const config = loggerService.getConfig();
    return reply.code(200).send(config);
  });

  // PATCH /logs
  server.patch('/logs', {
    preHandler: requireAuth(),
    schema: {
      body: updateLogConfigBodySchema,
      // REMOVED "response" schema
      response: {
        200: z.any(), // Allow any response type for success case
        400: errorResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const { channel, level } = request.body;

    // 1. Update
    loggerService.updateConfig(channel, level);

    // 2. Fetch fresh config
    const newConfig = loggerService.getConfig();

    // Send RAW config object
    return reply.code(200).send(newConfig);
  });

  // GET /permissions - Get all role permissions (GOD only)
  server.get('/permissions', {
    preHandler: requireAuth(),
    schema: {
      response: {
        200: getPermissionsResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const permissions = await getAllRolePermissions();
    return reply.code(200).send({
      success: true,
      data: permissions,
    });
  });

  // GET /permissions/my - Get permissions for current authenticated user role
  server.get('/permissions/my', {
    preHandler: requireAuth(),
    schema: {
      response: {
        200: getMyPermissionsResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const user = request.user as { role?: string } | undefined;
    if (!user?.role) {
      return reply.code(401).send({
        success: false,
        error: 'Authentication required',
      });
    }

    const permissions = await getRolePermissions(user.role);
    const enabledPermissions = permissions
      .filter((permission) => permission.isEnabled)
      .map((permission) => `${permission.resource}:${permission.action}`);
    return reply.code(200).send({
      success: true,
      data: enabledPermissions,
    });
  });

  // PUT /permissions - Bulk update role permissions (GOD only)
  server.put('/permissions', {
    preHandler: requireAuth(),
    schema: {
      body: bulkUpdatePermissionsSchema,
      response: {
        200: getPermissionsResponseSchema,
        400: errorResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const { permissions } = request.body;
    const updatedPermissions = await bulkUpdateRolePermissions(permissions);
    clearPermissionsCache();
    return reply.code(200).send({
      success: true,
      data: updatedPermissions,
    });
  });

  // GET /modules - Get all system modules (Public for frontend)
  server.get('/modules', {
    schema: {
      response: {
        200: getModulesResponseSchema,
      },
    },
  }, async (request, reply) => {
    const modules = await getAllSystemModules();
    return reply.code(200).send({
      success: true,
      data: modules,
    });
  });

  // PUT /modules - Bulk update system modules (GOD only)
  server.put('/modules', {
    preHandler: requireAuth(),
    schema: {
      body: bulkUpdateModulesSchema,
      response: {
        200: getModulesResponseSchema,
        400: errorResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const { modules } = request.body;
    const updatedModules = await bulkUpdateSystemModules(modules);
    return reply.code(200).send({
      success: true,
      data: updatedModules,
    });
  });

  // GET /role-colors - Get all role color schemes (ADMIN/GOD)
  server.get('/role-colors', {
    preHandler: requireAuth(),
    schema: {
      response: {
        200: getRoleColorsResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (_request, reply) => {
    const colors = await getAllRoleColors();

    return reply.code(200).send({
      success: true,
      data: colors,
    });
  });

  // PUT /role-colors/:role - Upsert role color scheme (ADMIN/GOD)
  server.put('/role-colors/:role', {
    preHandler: requireAuth(),
    schema: {
      params: roleParamSchema,
      body: updateRoleColorsBodySchema,
      response: {
        200: getRoleColorsResponseSchema,
        400: errorResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const user = request.user as { role?: string } | undefined;
    const isSystemAdmin = user?.role === USER_ROLES.ADMIN || user?.role === USER_ROLES.GOD;

    if (!isSystemAdmin) {
      return reply.code(403).send({
        success: false,
        error: 'Недостаточно прав для управления системными настройками',
      });
    }

    const { role } = request.params;
    await upsertRoleColors(role, request.body);
    const allColors = await getAllRoleColors();

    return reply.code(200).send({
      success: true,
      data: allColors,
    });
  });

  server.get('/session-policies', {
    preHandler: requireAuth(),
    schema: {
      response: {
        200: getSessionPoliciesResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (_request, reply) => {
    const policies = await getAllRoleSessionPolicies();
    return reply.code(200).send({
      success: true,
      data: policies,
    });
  });

  server.put('/session-policies', {
    preHandler: requireAuth(),
    schema: {
      body: bulkSessionPoliciesBodySchema,
      response: {
        200: getSessionPoliciesResponseSchema,
        400: errorResponseSchema,
        401: errorResponseSchema,
        403: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const { policies } = request.body;
    const updated = await bulkUpdateRoleSessionPolicies(policies);
    return reply.code(200).send({
      success: true,
      data: updated,
    });
  });

  server.get('/session-policies/my', {
    preHandler: requireAuth(),
    schema: {
      response: {
        200: z.object({ success: z.boolean(), data: sessionPolicySchema.nullable() }),
        401: errorResponseSchema,
      },
    },
  }, async (request, reply) => {
    const user = request.user as { role?: string } | undefined;
    if (!user?.role) {
      return reply.code(401).send({
        success: false,
        error: 'Authentication required',
      });
    }

    const policy = await getSessionPolicyForRole(user.role);
    if (!policy) {
      const allPolicies = await getAllRoleSessionPolicies();
      const p = allPolicies.find((pp) => pp.role === user.role);
      return reply.code(200).send({ success: true, data: p || null });
    }

    return reply.code(200).send({ success: true, data: policy });
  });
};
