import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { AdminUser } from '../../domain/entities/AdminUser';
import { AuthorizationService } from '../../domain/services/AuthorizationService';
import { Email } from '../../domain/value-objects/Email';
import { UserId } from '../../domain/value-objects/UserId';
import { UserRole } from '../../domain/value-objects/UserRole';
import { UserStatus } from '../../domain/value-objects/UserStatus';
import type { AdminUserRepository } from '../ports/AdminUserRepository';

export type ListUsersInput = {
  actorId: string;
  role?: string;
  status?: string;
  email?: string;
  search?: string;
  page?: number;
  limit?: number;
  sortBy?: 'email' | 'displayName' | 'createdAt' | 'lastLoginAt' | 'status';
  sortDirection?: 'asc' | 'desc';
};

export type ListUsersResult = {
  users: AdminUser[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
};

export type ListUsersErrorCode =
  | 'USER_NOT_FOUND'
  | 'VALIDATION_ERROR'
  | 'AUTHORIZATION_ERROR'
  | 'REPOSITORY_ERROR';

export type ListUsersApplicationError = ApplicationErrorCode<ListUsersErrorCode, { message: string; details?: unknown }>;

/**
 * Application Use Case: ListUsersUseCase
 *
 * Lists users with filtering, sorting, and pagination.
 * Only accessible to system administrators (Owner/Admin).
 */
export class ListUsersUseCase {
  constructor(
    private readonly adminUserRepository: AdminUserRepository,
  ) {}

  async execute(
    input: ListUsersInput,
  ): Promise<
    Result<
      ListUsersResult,
      ListUsersApplicationError
    >
  > {
    try {
      // Get actor (current user)
      const actor = await this.adminUserRepository.findById(UserId.fromString(input.actorId));
      if (!actor) {
        return Result.err({
          code: 'AUTHORIZATION_ERROR',
          details: { message: 'Actor not found' },
        });
      }

      // Check authorization
      if (!AuthorizationService.canListUsers(actor)) {
        return Result.err({
          code: 'AUTHORIZATION_ERROR',
          details: { message: 'User is not authorized to list users' },
        });
      }

      // Build filter
      const filter: {
        role?: UserRole;
        status?: UserStatus;
        email?: Email;
        search?: string;
      } = {};
      if (input.role) {
        filter.role = UserRole.fromString(input.role);
      }
      if (input.status) {
        filter.status = UserStatus.fromString(input.status);
      }
      if (input.email) {
        filter.email = Email.fromString(input.email);
      }
      if (input.search) {
        filter.search = input.search;
      }

      // Build sort
      const sort = input.sortBy ? {
        field: input.sortBy,
        direction: input.sortDirection || 'asc',
      } : undefined;

      // Build pagination
      const pagination = input.page && input.limit ? {
        page: input.page,
        limit: input.limit,
      } : undefined;

      // Execute query
      const query: {
        filter?: {
          role?: UserRole;
          status?: UserStatus;
          email?: Email;
          search?: string;
        };
        sort?: {
          field: 'email' | 'displayName' | 'createdAt' | 'lastLoginAt' | 'status';
          direction: 'asc' | 'desc';
        };
        pagination?: {
          page: number;
          limit: number;
        };
      } = {};
      
      if (Object.keys(filter).length > 0) {
        query.filter = filter;
      }
      if (sort) {
        query.sort = sort;
      }
      if (pagination) {
        query.pagination = pagination;
      }
      
      const result = await this.adminUserRepository.list(query);

      const output: ListUsersResult = {
        users: result.users,
        total: result.total,
        page: result.page,
        limit: result.limit,
        totalPages: result.totalPages,
      };

      return Result.ok(output);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to list users';

      if (error instanceof Error && error.message.includes('validation')) {
        return Result.err({
          code: 'VALIDATION_ERROR',
          details: { message },
        });
      }

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: { message },
      });
    }
  }
}
