import { db } from '../../config/database.js';
import { companyUsers, projectUsers, todoUsers } from '../../db/schema.js';
import { eq, and } from 'drizzle-orm';
import { logger } from '../../utils/logger.js';

/**
 * Univerzálny middleware pre kontrolu prístupu k resources
 * Admin má prístup vždy, member len ak je priradený k resource
 *
 * Použitie:
 *   checkResourceAccess('company', 'companyId')  // pre /companies/:companyId
 *   checkResourceAccess('project', 'projectId')  // pre /projects/:projectId
 *   checkResourceAccess('todo', 'todoId')        // pre /todos/:todoId
 */

// Mapovanie resource typu na junction tabuľku a stĺpce
const resourceConfig = {
  company: {
    table: companyUsers,
    resourceIdColumn: 'companyId',
  },
  project: {
    table: projectUsers,
    resourceIdColumn: 'projectId',
  },
  todo: {
    table: todoUsers,
    resourceIdColumn: 'todoId',
  },
};

/**
 * Skontroluje či user má prístup k danému resource
 * @param {string} resourceType - Typ resource ('company', 'project', atď.)
 * @param {string} userId - ID používateľa
 * @param {string} resourceId - ID resource
 * @returns {Promise<boolean>}
 */
export const hasAccessToResource = async (resourceType, userId, resourceId) => {
  const config = resourceConfig[resourceType];
  if (!config) {
    throw new Error(`Unknown resource type: ${resourceType}`);
  }

  const { table, resourceIdColumn } = config;

  const [assignment] = await db
    .select()
    .from(table)
    .where(and(
      eq(table[resourceIdColumn], resourceId),
      eq(table.userId, userId)
    ))
    .limit(1);

  return !!assignment;
};

/**
 * Middleware factory pre kontrolu prístupu k resource
 * @param {string} resourceType - Typ resource ('company', 'project')
 * @param {string} paramName - Názov parametra v URL (napr. 'companyId', 'projectId')
 */
export const checkResourceAccess = (resourceType, paramName) => {
  return async (req, res, next) => {
    // Skontroluj či je user autentifikovaný
    if (!req.user) {
      return res.status(401).json({
        success: false,
        error: {
          message: 'Musíte byť prihlásený',
          statusCode: 401,
        },
      });
    }

    // Admin má prístup vždy
    if (req.user.role === 'admin') {
      return next();
    }

    const resourceId = req.params[paramName];
    if (!resourceId) {
      return res.status(400).json({
        success: false,
        error: {
          message: `Chýba parameter ${paramName}`,
          statusCode: 400,
        },
      });
    }

    try {
      const hasAccess = await hasAccessToResource(resourceType, req.user.id, resourceId);

      if (!hasAccess) {
        return res.status(403).json({
          success: false,
          error: {
            message: 'Nemáte prístup k tomuto zdroju',
            statusCode: 403,
          },
        });
      }

      next();
    } catch (error) {
      logger.error('Resource access check error', error);
      return res.status(500).json({
        success: false,
        error: {
          message: 'Chyba pri overovaní prístupu',
          statusCode: 500,
        },
      });
    }
  };
};

/**
 * Helper funkcie pre bežné prípady
 */
export const checkCompanyAccess = checkResourceAccess('company', 'companyId');
export const checkProjectAccess = checkResourceAccess('project', 'projectId');
export const checkTodoAccess = checkResourceAccess('todo', 'todoId');

/**
 * Získa zoznam resource IDs ku ktorým má user prístup
 * Užitočné pre filtrovanie v service vrstvách
 * @param {string} resourceType - Typ resource ('company', 'project')
 * @param {string} userId - ID používateľa
 * @returns {Promise<string[]>} - Zoznam resource IDs
 */
export const getAccessibleResourceIds = async (resourceType, userId) => {
  const config = resourceConfig[resourceType];
  if (!config) {
    throw new Error(`Unknown resource type: ${resourceType}`);
  }

  const { table, resourceIdColumn } = config;

  const assignments = await db
    .select({ resourceId: table[resourceIdColumn] })
    .from(table)
    .where(eq(table.userId, userId));

  return assignments.map(a => a.resourceId);
};

/**
 * Skontroluje prístup a vráti boolean (pre použitie v services)
 * @param {string} resourceType
 * @param {string} userId
 * @param {string} resourceId
 * @param {string} userRole
 * @returns {Promise<boolean>}
 */
export const canAccessResource = async (resourceType, userId, resourceId, userRole) => {
  if (userRole === 'admin') return true;
  return hasAccessToResource(resourceType, userId, resourceId);
};
