import { Repository } from 'typeorm';
import { AppDataSource } from '../../config/typeorm.js';
import { State } from './entities/state.entity.js';
import { NotFoundError } from '../../shared/errors/index.js';
import { logger } from '../../shared/utils/logger.js';

export interface CreateStateDto {
  countryId: string;
  code: string;
  name: string;
  timezone?: string;
  isActive?: boolean;
}

export interface UpdateStateDto {
  name?: string;
  timezone?: string;
  isActive?: boolean;
}

export interface StateFilter {
  countryId?: string;
  countryCode?: string;
  isActive?: boolean;
}

class StatesService {
  private repository: Repository<State>;

  constructor() {
    this.repository = AppDataSource.getRepository(State);
  }

  async findAll(filter: StateFilter = {}): Promise<State[]> {
    logger.debug('Finding all states', { filter });

    const query = this.repository
      .createQueryBuilder('state')
      .leftJoinAndSelect('state.country', 'country');

    if (filter.countryId) {
      query.andWhere('state.countryId = :countryId', { countryId: filter.countryId });
    }

    if (filter.countryCode) {
      query.andWhere('country.code = :countryCode', { countryCode: filter.countryCode.toUpperCase() });
    }

    if (filter.isActive !== undefined) {
      query.andWhere('state.isActive = :isActive', { isActive: filter.isActive });
    }

    query.orderBy('state.name', 'ASC');

    return query.getMany();
  }

  async findById(id: string): Promise<State> {
    logger.debug('Finding state by id', { id });

    const state = await this.repository.findOne({
      where: { id },
      relations: ['country'],
    });

    if (!state) {
      throw new NotFoundError('Estado no encontrado');
    }

    return state;
  }

  async findByCode(countryId: string, code: string): Promise<State | null> {
    logger.debug('Finding state by code', { countryId, code });

    return this.repository.findOne({
      where: { countryId, code: code.toUpperCase() },
      relations: ['country'],
    });
  }

  async findByCountry(countryId: string): Promise<State[]> {
    logger.debug('Finding states by country', { countryId });

    return this.repository.find({
      where: { countryId, isActive: true },
      relations: ['country'],
      order: { name: 'ASC' },
    });
  }

  async findByCountryCode(countryCode: string): Promise<State[]> {
    logger.debug('Finding states by country code', { countryCode });

    return this.repository
      .createQueryBuilder('state')
      .leftJoinAndSelect('state.country', 'country')
      .where('country.code = :countryCode', { countryCode: countryCode.toUpperCase() })
      .andWhere('state.isActive = :isActive', { isActive: true })
      .orderBy('state.name', 'ASC')
      .getMany();
  }

  async create(dto: CreateStateDto): Promise<State> {
    logger.info('Creating state', { dto });

    // Check if state already exists for this country
    const existing = await this.findByCode(dto.countryId, dto.code);
    if (existing) {
      throw new Error(`Estado con código ${dto.code} ya existe para este país`);
    }

    const state = this.repository.create({
      ...dto,
      code: dto.code.toUpperCase(),
      isActive: dto.isActive ?? true,
    });

    return this.repository.save(state);
  }

  async update(id: string, dto: UpdateStateDto): Promise<State> {
    logger.info('Updating state', { id, dto });

    const state = await this.findById(id);
    Object.assign(state, dto);

    return this.repository.save(state);
  }

  async delete(id: string): Promise<void> {
    logger.info('Deleting state', { id });

    const state = await this.findById(id);
    await this.repository.remove(state);
  }

  async setActive(id: string, isActive: boolean): Promise<State> {
    logger.info('Setting state active status', { id, isActive });

    const state = await this.findById(id);
    state.isActive = isActive;

    return this.repository.save(state);
  }
}

export const statesService = new StatesService();
