import { Op } from 'sequelize';
import { HsnSacCode, HsnSacCodeAttributes, HsnSacCodeCreationAttributes } from '../models/HsnSacCode';
import logger from '../utils/logger';

export interface PaginatedHsnSacCodes {
  codes: HsnSacCode[];
  pagination: {
    totalRecords: number;
    totalPages: number;
    currentPage: number;
    limit: number;
  };
}

export class HsnSacCodeService {
  /**
   * Get HSN/SAC codes with pagination and search
   */
  async getAllCodes(
    onlyActive: boolean = false, 
    page: number = 1, 
    limit: number = 10, 
    search?: string
  ): Promise<PaginatedHsnSacCodes> {
    try {
      const where: any = {};
      if (onlyActive) {
        where.isActive = true;
      }

      if (search && search.trim()) {
        const searchTerm = `%${search.trim()}%`;
        where[Op.or] = [
          { code: { [Op.like]: searchTerm } },
          { description: { [Op.like]: searchTerm } }
        ];
      }

      const offset = (page - 1) * limit;

      const { count, rows } = await HsnSacCode.findAndCountAll({
        where,
        order: [['type', 'ASC'], ['code', 'ASC']],
        limit,
        offset
      });

      return {
        codes: rows,
        pagination: {
          totalRecords: count,
          totalPages: Math.ceil(count / limit),
          currentPage: page,
          limit
        }
      };
    } catch (error) {
      logger.error('Error fetching HSN/SAC codes:', error);
      throw error;
    }
  }

  /**
   * Get a single code by ID
   */
  async getCodeById(id: string): Promise<HsnSacCode | null> {
    try {
      return await HsnSacCode.findByPk(id);
    } catch (error) {
      logger.error(`Error fetching HSN/SAC code with id ${id}:`, error);
      throw error;
    }
  }

  /**
   * Create a new HSN/SAC code with duplicate check
   */
  async createCode(data: HsnSacCodeCreationAttributes): Promise<HsnSacCode> {
    try {
      // Check for duplicates
      const existing = await HsnSacCode.findOne({
        where: {
          code: data.code,
          type: data.type
        }
      });

      if (existing) {
        throw new Error(`${data.type} code "${data.code}" already exists`);
      }

      return await HsnSacCode.create(data);
    } catch (error) {
      logger.error('Error creating HSN/SAC code:', error);
      throw error;
    }
  }

  /**
   * Update an existing HSN/SAC code with duplicate check
   */
  async updateCode(id: string, data: Partial<HsnSacCodeAttributes>): Promise<HsnSacCode | null> {
    try {
      const code = await HsnSacCode.findByPk(id);
      if (!code) return null;

      // If code or type is being updated, check for duplicates
      if (data.code || data.type) {
        const existing = await HsnSacCode.findOne({
          where: {
            code: data.code || code.code,
            type: data.type || code.type,
            id: { [Op.ne]: id }
          }
        });

        if (existing) {
          throw new Error(`${data.type || code.type} code "${data.code || code.code}" already exists`);
        }
      }
      
      return await code.update(data);
    } catch (error) {
      logger.error(`Error updating HSN/SAC code with id ${id}:`, error);
      throw error;
    }
  }

  /**
   * Delete an HSN/SAC code
   */
  async deleteCode(id: string): Promise<boolean> {
    try {
      const result = await HsnSacCode.destroy({ where: { id } });
      return result > 0;
    } catch (error) {
      logger.error(`Error deleting HSN/SAC code with id ${id}:`, error);
      throw error;
    }
  }

  /**
   * Toggle active status
   */
  async toggleActive(id: string): Promise<HsnSacCode | null> {
    try {
      const code = await HsnSacCode.findByPk(id);
      if (!code) return null;
      
      return await code.update({ isActive: !code.isActive });
    } catch (error) {
      logger.error(`Error toggling active status for HSN/SAC code with id ${id}:`, error);
      throw error;
    }
  }
}

export const hsnSacCodeService = new HsnSacCodeService();
