import { Provider } from '@nestjs/common';

import {
    CREATE_TEAM_USE_CASE_TOKEN,
    DRIVER_REPOSITORY_TOKEN,
    GET_ALL_TEAMS_USE_CASE_TOKEN,
    GET_DRIVER_TEAM_USE_CASE_TOKEN,
    GET_TEAM_DETAILS_USE_CASE_TOKEN,
    GET_TEAM_JOIN_REQUESTS_USE_CASE_TOKEN,
    GET_TEAM_MEMBERS_USE_CASE_TOKEN,
    GET_TEAM_MEMBERSHIP_USE_CASE_TOKEN,
    IMAGE_SERVICE_TOKEN,
    JOIN_TEAM_USE_CASE_TOKEN,
    LOGGER_TOKEN,
    MEDIA_REPOSITORY_TOKEN,
    MEDIA_RESOLVER_TOKEN,
    TEAM_MEMBERSHIP_REPOSITORY_TOKEN,
    TEAM_REPOSITORY_TOKEN,
    TEAM_STATS_REPOSITORY_TOKEN,
    UPDATE_TEAM_USE_CASE_TOKEN,
    GET_TEAMS_LEADERBOARD_USE_CASE_TOKEN,
    DRIVER_STATS_REPOSITORY_TOKEN,
} from './TeamTokens';

export {
    DRIVER_REPOSITORY_TOKEN,
    IMAGE_SERVICE_TOKEN,
    LOGGER_TOKEN,
    MEDIA_REPOSITORY_TOKEN,
    MEDIA_RESOLVER_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, TEAM_REPOSITORY_TOKEN
} from './TeamTokens';

// Import core interfaces
import type { MediaResolverPort } from '@core/ports/media/MediaResolverPort';
import type { DriverRepository } from '@core/racing/domain/repositories/DriverRepository';
import type { TeamMembershipRepository } from '@core/racing/domain/repositories/TeamMembershipRepository';
import type { TeamRepository } from '@core/racing/domain/repositories/TeamRepository';
import type { TeamStatsRepository } from '@core/racing/domain/repositories/TeamStatsRepository';
import type { DriverStatsRepository } from '@core/racing/domain/repositories/DriverStatsRepository';
import type { Logger } from '@core/shared/domain/Logger';

// Import concrete implementations
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
import { MediaResolverAdapter } from '@adapters/media/MediaResolverAdapter';
import { InMemoryImageServiceAdapter } from '@adapters/media/ports/InMemoryImageServiceAdapter';
import { InMemoryMediaRepository } from '@adapters/racing/persistence/media/InMemoryMediaRepository';

// Import use cases
import { CreateTeamUseCase } from '@core/racing/application/use-cases/CreateTeamUseCase';
import { GetAllTeamsUseCase } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
import { GetTeamDetailsUseCase } from '@core/racing/application/use-cases/GetTeamDetailsUseCase';
import { GetTeamJoinRequestsUseCase } from '@core/racing/application/use-cases/GetTeamJoinRequestsUseCase';
import { GetTeamMembershipUseCase } from '@core/racing/application/use-cases/GetTeamMembershipUseCase';
import { GetTeamMembersUseCase } from '@core/racing/application/use-cases/GetTeamMembersUseCase';
import { JoinTeamUseCase } from '@core/racing/application/use-cases/JoinTeamUseCase';
import { UpdateTeamUseCase } from '@core/racing/application/use-cases/UpdateTeamUseCase';
import { GetTeamsLeaderboardUseCase } from '@core/racing/application/use-cases/GetTeamsLeaderboardUseCase';

// Import presenters
import { AllTeamsPresenter } from './presenters/AllTeamsPresenter';
import { TeamsLeaderboardPresenter } from './presenters/TeamsLeaderboardPresenter';

export const TeamProviders: Provider[] = [
  {
    provide: IMAGE_SERVICE_TOKEN,
    useFactory: (logger: Logger) => new InMemoryImageServiceAdapter(logger),
    inject: [LOGGER_TOKEN],
  },
  {
    provide: LOGGER_TOKEN,
    useClass: ConsoleLogger,
  },
  {
    provide: MEDIA_REPOSITORY_TOKEN,
    useFactory: (logger: Logger) => {
      const mediaRepo = new InMemoryMediaRepository(logger);
      
      // Override getTeamLogo to provide fallback URLs
      const originalGetTeamLogo = mediaRepo.getTeamLogo.bind(mediaRepo);
      mediaRepo.getTeamLogo = async (teamId: string): Promise<string | null> => {
        const logo = await originalGetTeamLogo(teamId);
        if (logo) return logo;
        
        // Fallback: generate deterministic team logo URL
        // Use API port (3001) for media generation
        const baseUrl = process.env.NODE_ENV === 'development' ? 'http://localhost:3001' : 'https://api.gridpilot.io';
        return `${baseUrl}/media/teams/${teamId}/logo`;
      };
      
      return mediaRepo;
    },
    inject: [LOGGER_TOKEN],
  },
  {
    provide: MEDIA_RESOLVER_TOKEN,
    useFactory: () => new MediaResolverAdapter({}),
  },
  {
    provide: AllTeamsPresenter,
    useFactory: (mediaResolver: MediaResolverPort) => {
      const presenter = new AllTeamsPresenter();
      presenter.setMediaResolver(mediaResolver);
      return presenter;
    },
    inject: [MEDIA_RESOLVER_TOKEN],
  },
  {
    provide: TeamsLeaderboardPresenter,
    useClass: TeamsLeaderboardPresenter,
  },
  // Use Cases
  {
    provide: GET_ALL_TEAMS_USE_CASE_TOKEN,
    useFactory: (teamRepo: TeamRepository, membershipRepo: TeamMembershipRepository, statsRepo: TeamStatsRepository, logger: Logger) =>
      new GetAllTeamsUseCase(teamRepo, membershipRepo, statsRepo, logger),
    inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, TEAM_STATS_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: GET_TEAM_DETAILS_USE_CASE_TOKEN,
    useFactory: (teamRepo: TeamRepository, membershipRepo: TeamMembershipRepository) =>
      new GetTeamDetailsUseCase(teamRepo, membershipRepo),
    inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN],
  },
  {
    provide: GET_TEAM_MEMBERS_USE_CASE_TOKEN,
    useFactory: (membershipRepo: TeamMembershipRepository, driverRepo: DriverRepository, teamRepo: TeamRepository, logger: Logger) =>
      new GetTeamMembersUseCase(membershipRepo, driverRepo, teamRepo, logger),
    inject: [TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, TEAM_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: GET_TEAM_JOIN_REQUESTS_USE_CASE_TOKEN,
    useFactory: (membershipRepo: TeamMembershipRepository, driverRepo: DriverRepository, teamRepo: TeamRepository) =>
      new GetTeamJoinRequestsUseCase(membershipRepo, driverRepo, teamRepo),
    inject: [TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, TEAM_REPOSITORY_TOKEN],
  },
  {
    provide: CREATE_TEAM_USE_CASE_TOKEN,
    useFactory: (teamRepo: TeamRepository, membershipRepo: TeamMembershipRepository, logger: Logger) =>
      new CreateTeamUseCase(teamRepo, membershipRepo, logger),
    inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: UPDATE_TEAM_USE_CASE_TOKEN,
    useFactory: (teamRepo: TeamRepository, membershipRepo: TeamMembershipRepository) =>
      new UpdateTeamUseCase(teamRepo, membershipRepo),
    inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN],
  },
  {
    provide: GET_DRIVER_TEAM_USE_CASE_TOKEN,
    useFactory: (teamRepo: TeamRepository, membershipRepo: TeamMembershipRepository, logger: Logger) =>
      new GetDriverTeamUseCase(teamRepo, membershipRepo, logger),
    inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: GET_TEAM_MEMBERSHIP_USE_CASE_TOKEN,
    useFactory: (membershipRepo: TeamMembershipRepository, logger: Logger) =>
      new GetTeamMembershipUseCase(membershipRepo, logger),
    inject: [TEAM_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: JOIN_TEAM_USE_CASE_TOKEN,
    useFactory: (teamRepo: TeamRepository, membershipRepo: TeamMembershipRepository, logger: Logger) =>
      new JoinTeamUseCase(teamRepo, membershipRepo, logger),
    inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
  {
    provide: GET_TEAMS_LEADERBOARD_USE_CASE_TOKEN,
    useFactory: async (teamRepo: TeamRepository, membershipRepo: TeamMembershipRepository, driverStatsRepo: DriverStatsRepository, logger: Logger) => {
      // Pre-fetch all driver stats for efficient lookup
      const allStats = await driverStatsRepo.getAllStats();
      
      return new GetTeamsLeaderboardUseCase(teamRepo, membershipRepo, (driverId) => {
        const stats = allStats.get(driverId);
        return stats ? { rating: stats.rating, wins: stats.wins, totalRaces: stats.totalRaces } : null;
      }, logger);
    },
    inject: [TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_STATS_REPOSITORY_TOKEN, LOGGER_TOKEN],
  },
];
