import { Injectable, NotFoundException, ConflictException, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, ILike } from 'typeorm';
import { LegalPage } from '../../../database/entities/legal-page.entity';
import { LegalPageVersion } from '../../../database/entities/legal-page-version.entity';
import {
  CreateLegalPageDto,
  UpdateLegalPageDto,
  LegalPageListFilter,
  LegalPageResponse,
  LegalPageVersionResponse,
} from './legal-pages.dto';

@Injectable()
export class LegalPagesService {
  constructor(
    @InjectRepository(LegalPage)
    private readonly legalPageRepository: Repository<LegalPage>,
    @InjectRepository(LegalPageVersion)
    private readonly legalPageVersionRepository: Repository<LegalPageVersion>,
  ) {}

  async findAll(filter: LegalPageListFilter = {}): Promise<LegalPage[]> {
    const where: any = {};

    if (filter.slug) {
      where.slug = filter.slug;
    }

    if (filter.language) {
      where.language = filter.language;
    }

    if (filter.isPublished !== undefined) {
      where.isPublished = filter.isPublished;
    }

    if (filter.search) {
      where.title = ILike(`%${filter.search}%`);
    }

    return this.legalPageRepository.find({
      where,
      relations: ['lastUpdatedByUser'],
      order: { createdAt: 'DESC' },
    });
  }

  async findOne(id: string): Promise<LegalPage> {
    const page = await this.legalPageRepository.findOne({
      where: { id },
      relations: ['lastUpdatedByUser', 'versions', 'versions.createdByUser'],
    });

    if (!page) {
      throw new NotFoundException(`Legal page with ID ${id} not found`);
    }

    return page;
  }

  async findBySlugAndLanguage(slug: string, language: string = 'en'): Promise<LegalPage | null> {
    return this.legalPageRepository.findOne({
      where: { slug, language, isPublished: true },
    });
  }

  async create(dto: CreateLegalPageDto, userId: string): Promise<LegalPage> {
    // Check if slug+language already exists
    const existing = await this.legalPageRepository.findOne({
      where: { slug: dto.slug, language: dto.language || 'en' },
    });

    if (existing) {
      throw new ConflictException(
        `Legal page with slug "${dto.slug}" and language "${dto.language || 'en'}" already exists`,
      );
    }

    const page = this.legalPageRepository.create({
      ...dto,
      version: 1,
      lastUpdatedBy: userId,
    });

    const savedPage = await this.legalPageRepository.save(page);

    // Create initial version
    await this.createVersion(savedPage.id, savedPage.title, savedPage.content, userId, 1);

    return this.findOne(savedPage.id);
  }

  async update(id: string, dto: UpdateLegalPageDto, userId: string): Promise<LegalPage> {
    const page = await this.findOne(id);

    // Increment version if content changed
    let newVersion = page.version;
    if (dto.content && dto.content !== page.content) {
      newVersion = page.version + 1;

      // Create version history
      await this.createVersion(
        page.id,
        dto.title || page.title,
        dto.content,
        userId,
        newVersion,
      );
    }

    // Update page
    Object.assign(page, {
      ...dto,
      version: newVersion,
      lastUpdatedBy: userId,
      updatedAt: new Date(),
    });

    await this.legalPageRepository.save(page);

    return this.findOne(id);
  }

  async publish(id: string, isPublished: boolean, userId: string): Promise<LegalPage> {
    const page = await this.findOne(id);

    page.isPublished = isPublished;
    page.lastUpdatedBy = userId;
    page.updatedAt = new Date();

    await this.legalPageRepository.save(page);

    return this.findOne(id);
  }

  async delete(id: string): Promise<void> {
    const page = await this.findOne(id);
    await this.legalPageRepository.remove(page);
  }

  async getVersionHistory(pageId: string): Promise<LegalPageVersion[]> {
    const page = await this.findOne(pageId);

    return this.legalPageVersionRepository.find({
      where: { legalPageId: page.id },
      relations: ['createdByUser'],
      order: { version: 'DESC' },
    });
  }

  async getVersionById(pageId: string, versionNumber: number): Promise<LegalPageVersion> {
    const version = await this.legalPageVersionRepository.findOne({
      where: { legalPageId: pageId, version: versionNumber },
      relations: ['createdByUser'],
    });

    if (!version) {
      throw new NotFoundException(
        `Version ${versionNumber} not found for legal page ${pageId}`,
      );
    }

    return version;
  }

  async revertToVersion(pageId: string, versionNumber: number, userId: string): Promise<LegalPage> {
    const page = await this.findOne(pageId);
    const targetVersion = await this.getVersionById(pageId, versionNumber);

    // Create a new version with reverted content
    const newVersion = page.version + 1;
    await this.createVersion(
      page.id,
      targetVersion.title,
      targetVersion.content,
      userId,
      newVersion,
    );

    // Update page with reverted content
    page.title = targetVersion.title;
    page.content = targetVersion.content;
    page.version = newVersion;
    page.lastUpdatedBy = userId;
    page.updatedAt = new Date();

    await this.legalPageRepository.save(page);

    return this.findOne(pageId);
  }

  private async createVersion(
    pageId: string,
    title: string,
    content: string,
    userId: string,
    versionNumber: number,
  ): Promise<LegalPageVersion> {
    const version = this.legalPageVersionRepository.create({
      legalPageId: pageId,
      version: versionNumber,
      title,
      content,
      createdBy: userId,
    });

    return this.legalPageVersionRepository.save(version);
  }

  // Helper method to transform entity to response
  toResponse(page: LegalPage): LegalPageResponse {
    return {
      id: page.id,
      slug: page.slug,
      title: page.title,
      content: page.content,
      language: page.language,
      version: page.version,
      isPublished: page.isPublished,
      lastUpdatedBy: page.lastUpdatedBy,
      createdAt: page.createdAt,
      updatedAt: page.updatedAt,
    };
  }

  toVersionResponse(version: LegalPageVersion): LegalPageVersionResponse {
    return {
      id: version.id,
      version: version.version,
      title: version.title,
      content: version.content,
      createdBy: version.createdBy,
      createdAt: version.createdAt,
    };
  }
}
