import { BadRequestException, Injectable } from '@nestjs/common';
import { CacheKeys } from '../common/utils/cache-keys';
import { PrismaService } from '../prisma/prisma.service';
import { RedisService } from '../redis/redis.service';
import { Country, State } from 'country-state-city';

@Injectable()
export class LocationsService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly redis: RedisService,
  ) {}

  async countries() {
    const cached = await this.redis.getJson(CacheKeys.countriesUploaded);
    if (cached) return { message: 'Countries fetched successfully', data: cached };

    const rows = await this.prisma.offlineMap.findMany({
      where: this.availableMapWhere(),
      distinct: ['countryName'],
      select: { countryName: true, countryCode: true },
      orderBy: { countryName: 'asc' },
    });

    const allCountries = Country.getAllCountries();
    const data = rows.map((row) => {
      const normalizedName = row.countryName.trim().toLowerCase();
      let country = row.countryCode
        ? Country.getCountryByCode(row.countryCode.toUpperCase())
        : undefined;
      if (!country) {
        country = allCountries.find((item) => item.name.trim().toLowerCase() === normalizedName);
      }
      return {
        name: row.countryName,
        code: row.countryCode ?? null,
        flag: country?.flag ?? '',
        region: '',
      };
    });

    await this.redis.setJson(CacheKeys.countriesUploaded, data, 900);
    return { message: 'Countries fetched successfully', data };
  }

  async states(country: string) {
    if (!country?.trim()) throw new BadRequestException('country query param is required');
    const key = CacheKeys.statesUploaded(country);
    const cached = await this.redis.getJson(key);
    if (cached) return { message: 'States fetched successfully', data: cached };

    const rows = await this.prisma.offlineMap.findMany({
      where: {
        ...this.availableMapWhere(),
        countryName: { equals: country.trim(), mode: 'insensitive' },
      },
      distinct: ['stateName'],
      select: { stateName: true },
      orderBy: { stateName: 'asc' },
    });

    const data = rows.map((row) => ({ name: row.stateName }));
    await this.redis.setJson(key, data, 900);
    return { message: 'States fetched successfully', data };
  }

  async allCountries() {
    const cached = await this.redis.getJson(CacheKeys.countriesAll);
    if (cached) return { message: 'Countries fetched successfully', data: cached };

    const data = Country.getAllCountries().map((item) => ({
      name: item.name,
      code: item.isoCode,
      flag: item.flag ?? '',
      region: '',
    }));

    await this.redis.setJson(CacheKeys.countriesAll, data, 900);
    return { message: 'Countries fetched successfully', data };
  }

  async allStates(country: string) {
    if (!country?.trim()) throw new BadRequestException('country query param is required');
    const key = CacheKeys.statesAll(country);
    const cached = await this.redis.getJson(key);
    if (cached) return { message: 'States fetched successfully', data: cached };

    const normalizedCountry = country.trim().toLowerCase();
    const countryRecord = Country.getAllCountries().find(
      (item) => item.isoCode.toLowerCase() === normalizedCountry || item.name.toLowerCase() === normalizedCountry,
    );

    const data = countryRecord
      ? State.getStatesOfCountry(countryRecord.isoCode).map((row) => ({ name: row.name }))
      : [];

    await this.redis.setJson(key, data, 900);
    return { message: 'States fetched successfully', data };
  }

  private availableMapWhere() {
    return {
      status: 'ACTIVE' as const,
      uploadStatus: 'COMPLETED' as const,
      deletedAt: null,
    };
  }
}
