import { EventTypeRepository } from '../models/repositories/EventTypeRepository';
import { UserRepository } from '../models/repositories/UserRepository';
import { AvailabilityRepository } from '../models/repositories/AvailabilityRepository';
import { AppError } from '../utils/AppError';
import { generateUuid } from '../utils/uuid';
import { EventType } from '../models/entities/EventType.entity';
import { CustomQuestion } from '../models/entities/EventType.entity';

export class EventTypeService {
  constructor(
    private eventTypeRepo = new EventTypeRepository(),
    private userRepo = new UserRepository(),
    private availabilityRepo = new AvailabilityRepository(),
  ) {}

  async list(userId: string): Promise<{ eventTypes: EventType[]; username: string }> {
    const user = await this.userRepo.findById(userId);
    if (!user) throw new AppError('not_found', 404, 'User not found.');
    const eventTypes = await this.eventTypeRepo.findByUserId(userId);
    return { eventTypes, username: user.username };
  }

  async create(
    userId: string,
    data: {
      slug: string;
      title: string;
      durationMinutes: number;
      bufferBeforeMinutes?: number;
      bufferAfterMinutes?: number;
      location?: string | null;
      meetingUrl?: string | null;
      description?: string;
      customQuestions?: CustomQuestion[];
      color?: string;
      bannerUrl?: string | null;
      logoUrl?: string | null;
      tagline?: string | null;
    },
  ): Promise<{ eventType: EventType; username: string }> {
    const user = await this.userRepo.findById(userId);
    if (!user) throw new AppError('not_found', 404, 'User not found.');

    const existing = await this.eventTypeRepo.findByUserAndSlug(userId, data.slug);
    if (existing) throw new AppError('validation_error', 400, 'Slug already exists.');

    const eventType = await this.eventTypeRepo.create({
      id: generateUuid(),
      userId,
      slug: data.slug,
      title: data.title,
      durationMinutes: data.durationMinutes,
      bufferBeforeMinutes: data.bufferBeforeMinutes ?? 0,
      bufferAfterMinutes: data.bufferAfterMinutes ?? 0,
      location: data.location ?? null,
      meetingUrl: data.meetingUrl ?? null,
      description: data.description ?? null,
      customQuestions: data.customQuestions ?? [],
      color: data.color ?? '#4F46E5',
      bannerUrl: data.bannerUrl ?? null,
      logoUrl: data.logoUrl ?? null,
      tagline: data.tagline ?? null,
      isActive: true,
    });

    await this.availabilityRepo.createSchedule({
      id: generateUuid(),
      userId,
      eventTypeId: eventType.id,
      minNoticeHours: 4,
      maxAdvanceDays: 60,
      timezone: user.timezone,
      weeklyRules: [],
    });

    return { eventType, username: user.username };
  }

  async update(userId: string, id: string, data: Partial<EventType>): Promise<{ eventType: EventType; username: string }> {
    const eventType = await this.eventTypeRepo.findById(id);
    if (!eventType || eventType.userId !== userId) {
      throw new AppError('not_found', 404, 'Event type not found.');
    }
    if (data.slug && data.slug !== eventType.slug) {
      const existing = await this.eventTypeRepo.findByUserAndSlug(userId, data.slug);
      if (existing && existing.id !== id) {
        throw new AppError('validation_error', 400, 'Slug already exists.');
      }
    }
    const user = await this.userRepo.findById(userId);
    const patch: Partial<EventType> = { ...data };
    if ('bannerUrl' in data) patch.bannerUrl = data.bannerUrl ?? null;
    if ('logoUrl' in data) patch.logoUrl = data.logoUrl ?? null;
    if ('tagline' in data) patch.tagline = data.tagline ?? null;
    if ('location' in data) patch.location = data.location ?? null;
    if ('meetingUrl' in data) patch.meetingUrl = data.meetingUrl ?? null;
    const updated = await this.eventTypeRepo.update(id, patch);
    return { eventType: updated, username: user!.username };
  }

  async delete(userId: string, id: string): Promise<void> {
    const eventType = await this.eventTypeRepo.findById(id);
    if (!eventType || eventType.userId !== userId) {
      throw new AppError('not_found', 404, 'Event type not found.');
    }
    const bookingCount = await this.eventTypeRepo.countBookings(id);
    if (bookingCount > 0) {
      await this.eventTypeRepo.softDelete(id);
    } else {
      await this.eventTypeRepo.hardDelete(id);
    }
  }
}
