// common/src/repositories/organization.repository.ts
import { Prisma, organizations } from "@prisma/client"
import { prisma } from "../prisma-client"
import { BaseRepository } from "./base-repository"

export class OrganizationRepository extends BaseRepository<
  organizations,
  Prisma.organizationsCreateInput,
  Prisma.organizationsUpdateInput
> {
  protected get model() {
    return this.prisma.organizations
  }

  /**
   * Find organization by GitHub organization ID
   */
  async findByGithubOrgId(github_org_id: string): Promise<organizations | null> {
    return await this.model.findUnique({
      where: { github_org_id },
    })
  }

  /**
   * Find organization by GitHub name
   */
  async findByGithubName(name: string): Promise<organizations | null> {
    return await this.model.findUnique({
      where: { name },
    })
  }

  /**
   * Find organizations where user is a member
   */
  async findByMember(userId: string): Promise<any[]> {
    return await this.model.findMany({
      where: {
        organization_members: {
          some: { user_id: userId },
        },
      },
      include: {
        organization_members: {
          where: { user_id: userId },
          select: { role: true },
        },
      },
      orderBy: { created_at: "desc" },
    })
  }

  /**
   * Find all organizations with member count
   */
  async findAllWithStats(): Promise<any[]> {
    return await this.model.findMany({
      include: {
        _count: {
          select: {
            organization_members: true,
            repositories: true,
          },
        },
      },
      orderBy: { created_at: "desc" },
    })
  }

  /**
   * Find organization with all related data
   */
  async findByIdWithRelations(id: string): Promise<any | null> {
    return await this.model.findUnique({
      where: { id },
      include: {
        organization_members: {
          include: {
            user: {
              select: {
                user_id: true,
                name: true,
                email: true,
                github_username: true,
              },
            },
          },
          orderBy: { added_at: "desc" },
        },
        repositories: {
          include: {
            _count: {
              select: {
                repository_members: true,
              },
            },
          },
          orderBy: { created_at: "desc" },
        },
        _count: {
          select: {
            organization_members: true,
            repositories: true,
          },
        },
      },
    })
  }

  /**
   * Upsert organization (create or update)
   */
  async upsertOrganization(data: {
    github_org_id?: string
    name: string
    website?: string
    auto_add_github_members?: boolean
    added_by?: string
  }): Promise<organizations> {
    const whereClause = data.github_org_id
      ? { github_org_id: data.github_org_id }
      : data.name
        ? { name: data.name }
        : undefined

    if (!whereClause) {
      throw new Error("Either github_org_id or github_login must be provided")
    }

    return await this.model.upsert({
      where: whereClause,
      update: {
        name: data.name,
        website: data.website,
        auto_add_github_members: data.auto_add_github_members,
      },
      create: {
        github_org_id: data.github_org_id,
        name: data.name,
        website: data.website,
        auto_add_github_members: data.auto_add_github_members ?? true,
        added_by: data.added_by,
      },
    })
  }

  /**
   * Search organizations by name or login
   */
  async searchByName(searchTerm: string, limit: number = 10): Promise<organizations[]> {
    return await this.model.findMany({
      where: {
        OR: [{ name: { contains: searchTerm, mode: "insensitive" } }],
      },
      take: limit,
      orderBy: { name: "asc" },
    })
  }

  /**
   * Update organization settings
   */
  async updateSettings(
    id: string,
    settings: {
      auto_add_github_members?: boolean
    },
  ): Promise<organizations> {
    return await this.model.update({
      where: { id },
      data: settings,
    })
  }

  /**
   * Get organization stats
   */
  async getStats(id: string): Promise<{
    memberCount: number
    repositoryCount: number
    activeRepositoryCount: number
  }> {
    const org = await this.model.findUnique({
      where: { id },
      include: {
        _count: {
          select: {
            organization_members: true,
            repositories: true,
          },
        },
        repositories: {
          where: { is_active: true },
          select: { id: true },
        },
      },
    })

    if (!org) {
      throw new Error("Organization not found")
    }

    return {
      memberCount: org._count.organization_members,
      repositoryCount: org._count.repositories,
      activeRepositoryCount: org.repositories.length,
    }
  }

  /**
   * Get organizations with their repository and member counts
   */
  async findWithCounts(options?: {
    skip?: number
    take?: number
    where?: Prisma.organizationsWhereInput
  }): Promise<any[]> {
    return await this.model.findMany({
      ...options,
      include: {
        _count: {
          select: {
            organization_members: true,
            repositories: true,
          },
        },
      },
      orderBy: { created_at: "desc" },
    })
  }

  /**
   * Update organization basic info
   */
  async updateInfo(
    id: string,
    data: {
      name?: string
      description?: string
      website?: string
    },
  ): Promise<organizations> {
    return await this.update(id, data)
  }
}

export const organizationRepository = new OrganizationRepository(prisma)
