// SPDX-License-Identifier: AGPL-3.0-or-later

import type {
	GuildCreateRequest,
	GuildUpdateRequest,
	GuildVanityURLUpdateResponse,
} from '@fluxer/schema/src/domains/guild/GuildRequestSchemas';
import type {
	GuildPartialResponse,
	GuildResponse,
	GuildVanityURLResponse,
} from '@fluxer/schema/src/domains/guild/GuildResponseSchemas';
import type {GuildID, UserID} from '../../BrandedTypes';
import type {IChannelRepository} from '../../channel/IChannelRepository';
import type {ChannelService} from '../../channel/services/ChannelService';
import type {EntityAssetService} from '../../infrastructure/EntityAssetService';
import type {IGatewayService} from '../../infrastructure/IGatewayService';
import type {ISnowflakeService} from '../../infrastructure/ISnowflakeService';
import type {InviteRepository} from '../../invite/InviteRepository';
import type {LimitConfigService} from '../../limits/LimitConfigService';
import type {RequestCache} from '../../middleware/RequestCacheMiddleware';
import type {Guild} from '../../models/Guild';
import type {GuildMember} from '../../models/GuildMember';
import type {User} from '../../models/User';
import type {IUserRepository} from '../../user/IUserRepository';
import type {IWebhookRepository} from '../../webhook/IWebhookRepository';
import type {GuildAuditLogService} from '../GuildAuditLogService';
import {GuildDiscoveryRepository} from '../repositories/GuildDiscoveryRepository';
import type {IGuildRepositoryAggregate} from '../repositories/IGuildRepositoryAggregate';
import {GuildDataHelpers} from './data/GuildDataHelpers';
import {GuildOperationsService} from './data/GuildOperationsService';
import {GuildOwnershipService} from './data/GuildOwnershipService';
import {GuildVanityService} from './data/GuildVanityService';

export class GuildDataService {
	private readonly helpers: GuildDataHelpers;
	private readonly operationsService: GuildOperationsService;
	private readonly vanityService: GuildVanityService;
	private readonly ownershipService: GuildOwnershipService;

	constructor(
		private readonly guildRepository: IGuildRepositoryAggregate,
		private readonly channelRepository: IChannelRepository,
		private readonly inviteRepository: InviteRepository,
		private readonly channelService: ChannelService,
		private readonly gatewayService: IGatewayService,
		private readonly entityAssetService: EntityAssetService,
		private readonly userRepository: IUserRepository,
		private readonly snowflakeService: ISnowflakeService,
		private readonly webhookRepository: IWebhookRepository,
		private readonly guildAuditLogService: GuildAuditLogService,
		private readonly limitConfigService: LimitConfigService,
	) {
		this.helpers = new GuildDataHelpers(this.gatewayService, this.guildAuditLogService, this.userRepository);
		this.operationsService = new GuildOperationsService(
			this.guildRepository,
			this.channelRepository,
			this.inviteRepository,
			this.channelService,
			this.gatewayService,
			this.entityAssetService,
			this.userRepository,
			this.snowflakeService,
			this.webhookRepository,
			this.helpers,
			this.limitConfigService,
			new GuildDiscoveryRepository(),
		);
		this.vanityService = new GuildVanityService(this.guildRepository, this.inviteRepository, this.helpers);
		this.ownershipService = new GuildOwnershipService(this.guildRepository, this.userRepository, this.helpers);
	}

	async getGuild({userId, guildId}: {userId: UserID; guildId: GuildID}): Promise<GuildResponse> {
		return this.operationsService.getGuild({userId, guildId});
	}

	async getUserGuilds(
		userId: UserID,
		options?: {
			before?: GuildID;
			after?: GuildID;
			limit?: number;
			withCounts?: boolean;
		},
	): Promise<Array<GuildResponse>> {
		return this.operationsService.getUserGuilds(userId, options);
	}

	async getPublicGuildData(guildId: GuildID): Promise<GuildPartialResponse> {
		return this.operationsService.getPublicGuildData(guildId);
	}

	async getGuildSystem(guildId: GuildID): Promise<Guild> {
		return this.operationsService.getGuildSystem(guildId);
	}

	async createGuild(
		params: {
			user: User;
			data: GuildCreateRequest;
			locale?: string | null;
		},
		auditLogReason?: string | null,
	): Promise<GuildResponse> {
		return this.operationsService.createGuild(params, auditLogReason);
	}

	async updateGuild(
		params: {
			userId: UserID;
			guildId: GuildID;
			data: GuildUpdateRequest;
			requestCache: RequestCache;
		},
		auditLogReason?: string | null,
	): Promise<{
		guild: GuildResponse;
		previousFeatures: Set<string>;
		updatedFeatures: Set<string>;
	}> {
		return this.operationsService.updateGuild(params, auditLogReason);
	}

	async getVanityURL(params: {userId: UserID; guildId: GuildID}): Promise<GuildVanityURLResponse> {
		return this.vanityService.getVanityURL(params);
	}

	async updateVanityURL(
		params: {
			userId: UserID;
			guildId: GuildID;
			code: string | null;
			requestCache: RequestCache;
		},
		auditLogReason?: string | null,
	): Promise<GuildVanityURLUpdateResponse> {
		return this.vanityService.updateVanityURL(params, auditLogReason);
	}

	async deleteGuild(
		params: {
			user: User;
			guildId: GuildID;
		},
		auditLogReason?: string | null,
	): Promise<void> {
		return this.operationsService.deleteGuild(params, auditLogReason);
	}

	async deleteGuildForAdmin(guildId: GuildID, _auditLogReason?: string | null): Promise<void> {
		return this.operationsService.deleteGuildById(guildId);
	}

	async transferOwnership(
		params: {
			userId: UserID;
			guildId: GuildID;
			newOwnerId: UserID;
		},
		auditLogReason?: string | null,
	): Promise<GuildResponse> {
		return this.ownershipService.transferOwnership(params, auditLogReason);
	}

	async checkGuildVerification(params: {user: User; guild: Guild; member: GuildMember}): Promise<void> {
		return this.ownershipService.checkGuildVerification(params);
	}
}
