import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { Province, City, UserRegionMapping, Prisma } from '@prisma/client';

export interface CreateProvinceInput {
  code: string;
  name: string;
}

export interface CreateCityInput {
  provinceId: string;
  code: string;
  name: string;
}

export interface AssignUserRegionInput {
  accountSequence: string;
  cityId: string;
  assignedBy?: string;
}

@Injectable()
export class RegionRepository {
  private readonly logger = new Logger(RegionRepository.name);

  constructor(private readonly prisma: PrismaService) {}

  // ==================== Province Operations ====================

  async createProvince(input: CreateProvinceInput): Promise<Province> {
    return this.prisma.province.create({
      data: {
        code: input.code,
        name: input.name,
      },
    });
  }

  async findProvinceById(id: string): Promise<Province | null> {
    return this.prisma.province.findUnique({
      where: { id },
      include: { cities: true },
    });
  }

  async findProvinceByCode(code: string): Promise<Province | null> {
    return this.prisma.province.findUnique({
      where: { code },
      include: { cities: true },
    });
  }

  async findAllProvinces(): Promise<Province[]> {
    return this.prisma.province.findMany({
      where: { status: 'ACTIVE' },
      include: { cities: true },
      orderBy: { code: 'asc' },
    });
  }

  async updateProvinceStatus(id: string, status: string): Promise<Province> {
    return this.prisma.province.update({
      where: { id },
      data: { status },
    });
  }

  // ==================== City Operations ====================

  async createCity(input: CreateCityInput): Promise<City> {
    return this.prisma.city.create({
      data: {
        provinceId: input.provinceId,
        code: input.code,
        name: input.name,
      },
      include: { province: true },
    });
  }

  async findCityById(id: string): Promise<City | null> {
    return this.prisma.city.findUnique({
      where: { id },
      include: { province: true },
    });
  }

  async findCityByCode(code: string): Promise<City | null> {
    return this.prisma.city.findUnique({
      where: { code },
      include: { province: true },
    });
  }

  async findCitiesByProvince(provinceId: string): Promise<City[]> {
    return this.prisma.city.findMany({
      where: {
        provinceId,
        status: 'ACTIVE',
      },
      include: { province: true },
      orderBy: { code: 'asc' },
    });
  }

  async findAllCities(): Promise<City[]> {
    return this.prisma.city.findMany({
      where: { status: 'ACTIVE' },
      include: { province: true },
      orderBy: [{ province: { code: 'asc' } }, { code: 'asc' }],
    });
  }

  async updateCityStatus(id: string, status: string): Promise<City> {
    return this.prisma.city.update({
      where: { id },
      data: { status },
    });
  }

  // ==================== User Region Mapping Operations ====================

  async assignUserToRegion(input: AssignUserRegionInput): Promise<UserRegionMapping> {
    return this.prisma.userRegionMapping.upsert({
      where: {
        accountSequence: input.accountSequence,
      },
      create: {
        accountSequence: input.accountSequence,
        cityId: input.cityId,
        assignedBy: input.assignedBy,
      },
      update: {
        cityId: input.cityId,
        assignedBy: input.assignedBy,
        assignedAt: new Date(),
      },
      include: {
        city: {
          include: { province: true },
        },
      },
    });
  }

  async findUserRegion(accountSequence: string): Promise<UserRegionMapping | null> {
    return this.prisma.userRegionMapping.findUnique({
      where: { accountSequence },
      include: {
        city: {
          include: { province: true },
        },
      },
    });
  }

  async findUsersByCity(cityId: string, options?: {
    limit?: number;
    offset?: number;
  }): Promise<{ mappings: UserRegionMapping[]; total: number }> {
    const [mappings, total] = await Promise.all([
      this.prisma.userRegionMapping.findMany({
        where: { cityId },
        include: {
          city: {
            include: { province: true },
          },
        },
        take: options?.limit || 50,
        skip: options?.offset || 0,
        orderBy: { assignedAt: 'desc' },
      }),
      this.prisma.userRegionMapping.count({ where: { cityId } }),
    ]);

    return { mappings, total };
  }

  async findUsersByProvince(provinceId: string, options?: {
    limit?: number;
    offset?: number;
  }): Promise<{ mappings: UserRegionMapping[]; total: number }> {
    const where: Prisma.UserRegionMappingWhereInput = {
      city: {
        provinceId,
      },
    };

    const [mappings, total] = await Promise.all([
      this.prisma.userRegionMapping.findMany({
        where,
        include: {
          city: {
            include: { province: true },
          },
        },
        take: options?.limit || 50,
        skip: options?.offset || 0,
        orderBy: { assignedAt: 'desc' },
      }),
      this.prisma.userRegionMapping.count({ where }),
    ]);

    return { mappings, total };
  }

  async removeUserFromRegion(accountSequence: string): Promise<void> {
    await this.prisma.userRegionMapping.delete({
      where: { accountSequence },
    }).catch(() => {
      // Ignore if not found
    });
  }

  // ==================== Statistics ====================

  async getRegionStats(): Promise<{
    provinces: {
      id: string;
      code: string;
      name: string;
      cityCount: number;
      userCount: number;
    }[];
    totalProvinces: number;
    totalCities: number;
    totalMappedUsers: number;
  }> {
    const provinces = await this.prisma.province.findMany({
      where: { status: 'ACTIVE' },
      include: {
        cities: {
          where: { status: 'ACTIVE' },
          include: {
            _count: {
              select: { userMappings: true },
            },
          },
        },
      },
    });

    const provinceStats = provinces.map((p) => ({
      id: p.id,
      code: p.code,
      name: p.name,
      cityCount: p.cities.length,
      userCount: p.cities.reduce((sum, c) => sum + c._count.userMappings, 0),
    }));

    const totalCities = await this.prisma.city.count({ where: { status: 'ACTIVE' } });
    const totalMappedUsers = await this.prisma.userRegionMapping.count();

    return {
      provinces: provinceStats,
      totalProvinces: provinces.length,
      totalCities,
      totalMappedUsers,
    };
  }

  /**
   * 批量初始化区域数据
   */
  async bulkInitializeRegions(
    regions: { provinceCode: string; provinceName: string; cities: { code: string; name: string }[] }[],
  ): Promise<void> {
    await this.prisma.$transaction(async (tx) => {
      for (const region of regions) {
        const province = await tx.province.upsert({
          where: { code: region.provinceCode },
          create: {
            code: region.provinceCode,
            name: region.provinceName,
          },
          update: {
            name: region.provinceName,
          },
        });

        for (const city of region.cities) {
          await tx.city.upsert({
            where: { code: city.code },
            create: {
              provinceId: province.id,
              code: city.code,
              name: city.name,
            },
            update: {
              name: city.name,
            },
          });
        }
      }
    });
  }
}
