import { Inject, Injectable } from '@nestjs/common';
import { AvailableLeagueDTO } from './dtos/AvailableLeagueDTO';
import { BillingStatsDTO } from './dtos/BillingStatsDTO';
import { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO';
import { CreateSponsorOutputDTO } from './dtos/CreateSponsorOutputDTO';
import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshipPricingResultDTO';
import { GetPendingSponsorshipRequestsOutputDTO } from './dtos/GetPendingSponsorshipRequestsOutputDTO';
import { GetSponsorDashboardQueryParamsDTO } from './dtos/GetSponsorDashboardQueryParamsDTO';
import { GetSponsorOutputDTO } from './dtos/GetSponsorOutputDTO';
import { GetSponsorsOutputDTO } from './dtos/GetSponsorsOutputDTO';
import { GetSponsorSponsorshipsQueryParamsDTO } from './dtos/GetSponsorSponsorshipsQueryParamsDTO';
import { InvoiceDTO } from './dtos/InvoiceDTO';
import { LeagueDetailDTO } from './dtos/LeagueDetailDTO';
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
import { PaymentMethodDTO } from './dtos/PaymentMethodDTO';
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
import { SponsorRaceDTO } from './dtos/RaceDTO';
import { SponsorDashboardDTO } from './dtos/SponsorDashboardDTO';
import { SponsorDriverDTO } from './dtos/SponsorDriverDTO';
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
import { SponsorSponsorshipsDTO } from './dtos/SponsorSponsorshipsDTO';

// Use cases
import { GetSponsorBillingUseCase } from '@core/payments/application/use-cases/GetSponsorBillingUseCase';
import { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
import { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateSponsorUseCase';
import { GetEntitySponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
import {
    GetPendingSponsorshipRequestsInput,
    GetPendingSponsorshipRequestsUseCase,
} from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
import { GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
import { GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
import { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase';
import { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase';
import { RejectSponsorshipRequestUseCase } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
import type { SponsorableEntityType } from '@core/racing/domain/entities/SponsorshipRequest';
import type { Logger } from '@core/shared/domain/Logger';

// Tokens
import {
    ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
    CREATE_SPONSOR_USE_CASE_TOKEN,
    GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
    GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN,
    GET_SPONSOR_BILLING_USE_CASE_TOKEN,
    GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
    GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN,
    GET_SPONSOR_USE_CASE_TOKEN,
    GET_SPONSORS_USE_CASE_TOKEN,
    LOGGER_TOKEN,
    REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
} from './SponsorTokens';

// Presenters (for view model transformation only)
import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
import type { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter';
import { AvailableLeaguesPresenter } from './presenters/AvailableLeaguesPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter';
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
import { GetSponsorPresenter } from './presenters/GetSponsorPresenter';
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
import { LeagueDetailPresenter } from './presenters/LeagueDetailPresenter';
import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter';
import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter';
import { SponsorSettingsPresenter } from './presenters/SponsorSettingsPresenter';
import { SponsorSettingsUpdatePresenter } from './presenters/SponsorSettingsUpdatePresenter';

@Injectable()
export class SponsorService {
  constructor(
    @Inject(GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN)
    private readonly getEntitySponsorshipPricingUseCase: GetEntitySponsorshipPricingUseCase,
    @Inject(GET_SPONSORS_USE_CASE_TOKEN)
    private readonly getSponsorsUseCase: GetSponsorsUseCase,
    @Inject(CREATE_SPONSOR_USE_CASE_TOKEN)
    private readonly createSponsorUseCase: CreateSponsorUseCase,
    @Inject(GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN)
    private readonly getSponsorDashboardUseCase: GetSponsorDashboardUseCase,
    @Inject(GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN)
    private readonly getSponsorSponsorshipsUseCase: GetSponsorSponsorshipsUseCase,
    @Inject(GET_SPONSOR_USE_CASE_TOKEN)
    private readonly getSponsorUseCase: GetSponsorUseCase,
    @Inject(GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN)
    private readonly getPendingSponsorshipRequestsUseCase: GetPendingSponsorshipRequestsUseCase,
    @Inject(ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN)
    private readonly acceptSponsorshipRequestUseCase: AcceptSponsorshipRequestUseCase,
    @Inject(REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN)
    private readonly rejectSponsorshipRequestUseCase: RejectSponsorshipRequestUseCase,
    @Inject(GET_SPONSOR_BILLING_USE_CASE_TOKEN)
    private readonly getSponsorBillingUseCase: GetSponsorBillingUseCase,
    @Inject(LOGGER_TOKEN)
    private readonly logger: Logger,
  ) {}

  async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
    this.logger.debug('[SponsorService] Fetching sponsorship pricing.');
    const result = await this.getEntitySponsorshipPricingUseCase.execute({
      entityType: 'season',
      entityId: 'default',
    });

    if (result.isErr()) {
      return {
        entityType: 'season',
        entityId: '',
        pricing: [],
      };
    }

    const presenter = new GetEntitySponsorshipPricingPresenter();
    presenter.present(result.value);
    return presenter.viewModel;
  }

  async getSponsors(): Promise<GetSponsorsOutputDTO> {
    this.logger.debug('[SponsorService] Fetching sponsors.');
    const result = await this.getSponsorsUseCase.execute({});

    if (result.isErr()) {
      return { sponsors: [] };
    }

    const presenter = new GetSponsorsPresenter();
    presenter.present(result.unwrap().sponsors);
    return presenter.responseModel;
  }

  async createSponsor(input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
    this.logger.debug('[SponsorService] Creating sponsor.', { input });
    const result = await this.createSponsorUseCase.execute(input);

    if (result.isErr()) {
      const error = result.unwrapErr() as { details?: { message?: string }; message?: string };
      throw new Error(error.details?.message ?? error.message ?? 'Failed to create sponsor');
    }

    const resultValue = result.value;
    if (!resultValue) {
      throw new Error('Create sponsor failed');
    }

    const presenter = new CreateSponsorPresenter();
    presenter.present(resultValue.sponsor);
    return presenter.viewModel;
  }

  async getSponsorDashboard(
    params: GetSponsorDashboardQueryParamsDTO,
  ): Promise<SponsorDashboardDTO> {
    this.logger.debug('[SponsorService] Fetching sponsor dashboard.', { params });
    const result = await this.getSponsorDashboardUseCase.execute(params);

    if (result.isErr()) {
      throw new Error('Sponsor dashboard not found');
    }

    const resultValue = result.value;
    if (!resultValue) {
      throw new Error('Sponsor dashboard not found');
    }

    const presenter = new GetSponsorDashboardPresenter();
    presenter.present(resultValue);
    return presenter.viewModel;
  }

  async getSponsorSponsorships(
    params: GetSponsorSponsorshipsQueryParamsDTO,
  ): Promise<SponsorSponsorshipsDTO> {
    this.logger.debug('[SponsorService] Fetching sponsor sponsorships.', { params });
    const result = await this.getSponsorSponsorshipsUseCase.execute(params);

    if (result.isErr()) {
      throw new Error('Sponsor sponsorships not found');
    }

    const resultValue = result.value;
    if (!resultValue) {
      throw new Error('Sponsor sponsorships not found');
    }

    const presenter = new GetSponsorSponsorshipsPresenter();
    presenter.present(resultValue);
    return presenter.viewModel;
  }

  async getSponsor(sponsorId: string): Promise<GetSponsorOutputDTO> {
    this.logger.debug('[SponsorService] Fetching sponsor.', { sponsorId });
    const result = await this.getSponsorUseCase.execute({ sponsorId });

    if (result.isErr()) {
      throw new Error('Sponsor not found');
    }

    const resultValue = result.value;
    if (!resultValue) {
      throw new Error('Sponsor not found');
    }

    const presenter = new GetSponsorPresenter();
    presenter.present(resultValue.sponsor);
    const viewModel = presenter.viewModel;
    if (!viewModel) {
      throw new Error('Sponsor not found');
    }
    return viewModel;
  }

  async getPendingSponsorshipRequests(params: {
    entityType: SponsorableEntityType;
    entityId: string;
  }): Promise<GetPendingSponsorshipRequestsOutputDTO> {
    this.logger.debug('[SponsorService] Fetching pending sponsorship requests.', { params });

    const result = await this.getPendingSponsorshipRequestsUseCase.execute(
      params as GetPendingSponsorshipRequestsInput,
    );

    if (result.isErr()) {
      return {
        entityType: params.entityType,
        entityId: params.entityId,
        requests: [],
        totalCount: 0,
      };
    }

    const resultValue = result.value;
    if (!resultValue) {
      throw new Error('Pending sponsorship requests not found');
    }

    const presenter = new GetPendingSponsorshipRequestsPresenter();
    presenter.present(resultValue);
    const viewModel = presenter.viewModel;
    if (!viewModel) {
      throw new Error('Pending sponsorship requests not found');
    }

    return viewModel;
  }

  async acceptSponsorshipRequest(
    requestId: string,
    respondedBy: string,
  ): Promise<AcceptSponsorshipRequestResultViewModel> {
    this.logger.debug('[SponsorService] Accepting sponsorship request.', {
      requestId,
      respondedBy,
    });

    const result = await this.acceptSponsorshipRequestUseCase.execute({
      requestId,
      respondedBy,
    });

    if (result.isErr()) {
      throw new Error('Accept sponsorship request failed');
    }

    const resultValue = result.value;
    if (!resultValue) {
      throw new Error('Accept sponsorship request failed');
    }

    const presenter = new AcceptSponsorshipRequestPresenter();
    presenter.present(resultValue);
    const viewModel = presenter.viewModel;
    if (!viewModel) {
      throw new Error('Accept sponsorship request failed');
    }

    return viewModel;
  }

  async rejectSponsorshipRequest(
    requestId: string,
    respondedBy: string,
    reason?: string,
  ): Promise<RejectSponsorshipRequestResult> {
    this.logger.debug('[SponsorService] Rejecting sponsorship request.', {
      requestId,
      respondedBy,
      reason,
    });
    const input: { requestId: string; respondedBy: string; reason?: string } = {
      requestId,
      respondedBy,
    };
    if (reason !== undefined) {
      input.reason = reason;
    }

    const result = await this.rejectSponsorshipRequestUseCase.execute(input);

    if (result.isErr()) {
      throw new Error('Reject sponsorship request failed');
    }

    const resultValue = result.value;
    if (!resultValue) {
      throw new Error('Reject sponsorship request failed');
    }

    const presenter = new RejectSponsorshipRequestPresenter();
    presenter.present(resultValue);
    const viewModel = presenter.viewModel;
    if (!viewModel) {
      throw new Error('Reject sponsorship request failed');
    }

    return viewModel;
  }

  async getSponsorBilling(sponsorId: string): Promise<{
    paymentMethods: PaymentMethodDTO[];
    invoices: InvoiceDTO[];
    stats: BillingStatsDTO;
  }> {
    this.logger.debug('[SponsorService] Fetching sponsor billing.', { sponsorId });
    const result = await this.getSponsorBillingUseCase.execute({ sponsorId });

    if (result.isErr()) {
      throw new Error('Sponsor billing not found');
    }

    const billingData = result.unwrap();
    const presenter = new SponsorBillingPresenter();
    presenter.present({
      paymentMethods: billingData.paymentMethods,
      invoices: billingData.invoices,
      stats: {
        ...billingData.stats,
        nextPaymentDate: billingData.stats.nextPaymentDate ?? '',
        nextPaymentAmount: billingData.stats.nextPaymentAmount ?? 0,
      },
    });

    return presenter.viewModel;
  }

  async getAvailableLeagues(): Promise<AvailableLeaguesPresenter> {
    this.logger.debug('[SponsorService] Fetching available leagues.');

    const presenter = new AvailableLeaguesPresenter();

    const leagues: AvailableLeagueDTO[] = [
      {
        id: 'league-1',
        name: 'GT3 Masters Championship',
        game: 'iRacing',
        drivers: 48,
        avgViewsPerRace: 8200,
        mainSponsorSlot: { available: true, price: 1200 },
        secondarySlots: { available: 1, total: 2, price: 400 },
        rating: 4.8,
        tier: 'premium',
        nextRace: '2025-12-20',
        seasonStatus: 'active',
        description:
          'Premier GT3 racing with top-tier drivers. Weekly broadcasts and active community.',
      },
      {
        id: 'league-2',
        name: 'Endurance Pro Series',
        game: 'ACC',
        drivers: 72,
        avgViewsPerRace: 12500,
        mainSponsorSlot: { available: false, price: 1500 },
        secondarySlots: { available: 2, total: 2, price: 500 },
        rating: 4.9,
        tier: 'premium',
        nextRace: '2026-01-05',
        seasonStatus: 'active',
        description:
          'Multi-class endurance racing. High engagement from dedicated endurance fans.',
      },
    ];

    presenter.present(leagues);
    return presenter;
  }

  async getLeagueDetail(leagueId: string): Promise<LeagueDetailPresenter> {
    this.logger.debug('[SponsorService] Fetching league detail.', { leagueId });

    const presenter = new LeagueDetailPresenter();

    // Mock data
    const league: LeagueDetailDTO = {
      id: leagueId,
      name: 'GT3 Masters Championship',
      game: 'iRacing',
      tier: 'premium',
      season: 'Season 3',
      description:
        "Premier GT3 racing with top-tier drivers competing across the world's most iconic circuits.",
      drivers: 48,
      races: 12,
      completedRaces: 8,
      totalImpressions: 45200,
      avgViewsPerRace: 5650,
      engagement: 4.2,
      rating: 4.8,
      seasonStatus: 'active',
      seasonDates: { start: '2025-10-01', end: '2026-02-28' },
      nextRace: { name: 'Spa-Francorchamps', date: '2025-12-20' },
      sponsorSlots: {
        main: {
          available: true,
          price: 1200,
          benefits: [
            'Primary logo placement on all liveries',
            'League page header banner',
            'Race results page branding',
            'Social media feature posts',
            'Newsletter sponsor spot',
          ],
        },
        secondary: {
          available: 1,
          total: 2,
          price: 400,
          benefits: [
            'Secondary logo on liveries',
            'League page sidebar placement',
            'Race results mention',
            'Social media mentions',
          ],
        },
      },
    };

    const drivers: SponsorDriverDTO[] = [
      {
        id: 'd1',
        name: 'Max Verstappen',
        country: 'NL',
        position: 1,
        races: 8,
        impressions: 4200,
        team: 'Red Bull Racing',
      },
      {
        id: 'd2',
        name: 'Lewis Hamilton',
        country: 'GB',
        position: 2,
        races: 8,
        impressions: 3980,
        team: 'Mercedes AMG',
      },
    ];

    const races: SponsorRaceDTO[] = [
      {
        id: 'r1',
        name: 'Spa-Francorchamps',
        date: '2025-12-20',
        views: 0,
        status: 'upcoming',
      },
      {
        id: 'r2',
        name: 'Monza',
        date: '2025-12-08',
        views: 5800,
        status: 'completed',
      },
    ];

    presenter.present({ league, drivers, races });
    return presenter;
  }

  async getSponsorSettings(sponsorId: string): Promise<SponsorSettingsPresenter> {
    this.logger.debug('[SponsorService] Fetching sponsor settings.', { sponsorId });

    const presenter = new SponsorSettingsPresenter();

    // Mock data
    const profile: SponsorProfileDTO = {
      companyName: 'Acme Racing Co.',
      contactName: 'John Smith',
      contactEmail: 'sponsor@acme-racing.com',
      contactPhone: '+1 (555) 123-4567',
      website: 'https://acme-racing.com',
      description:
        'Premium sim racing equipment and accessories for competitive drivers.',
      logoUrl: '',
      industry: 'Racing Equipment',
      address: {
        street: '123 Racing Boulevard',
        city: 'Indianapolis',
        country: 'United States',
        postalCode: '46222',
      },
      taxId: 'US12-3456789',
      socialLinks: {
        twitter: '@acmeracing',
        linkedin: 'acme-racing-co',
        instagram: '@acmeracing',
      },
    };

    const notifications: NotificationSettingsDTO = {
      emailNewSponsorships: true,
      emailWeeklyReport: true,
      emailRaceAlerts: false,
      emailPaymentAlerts: true,
      emailNewOpportunities: true,
      emailContractExpiry: true,
    };

    const privacy: PrivacySettingsDTO = {
      publicProfile: true,
      showStats: false,
      showActiveSponsorships: true,
      allowDirectContact: true,
    };

    presenter.present({ profile, notifications, privacy });
    return presenter;
  }

  async updateSponsorSettings(
    sponsorId: string,
    input: {
      profile?: Partial<SponsorProfileDTO>;
      notifications?: Partial<NotificationSettingsDTO>;
      privacy?: Partial<PrivacySettingsDTO>;
    },
  ): Promise<SponsorSettingsUpdatePresenter> {
    this.logger.debug('[SponsorService] Updating sponsor settings.', { sponsorId, input });

    // Mock implementation - in real app, this would persist to database
    this.logger.info('[SponsorService] Settings updated successfully.', { sponsorId });

    const presenter = new SponsorSettingsUpdatePresenter();
    presenter.present({ success: true });
    return presenter;
  }
}