import axios from 'axios'

export interface DaDataCompany {
  value: string
  unrestricted_value: string
  data: {
    kpp?: string
    management?: {
      name?: string
      post?: string
    }
    hid: string
    type: string
    state?: {
      status?: string
      actuality_date?: number
      registration_date?: number
      liquidation_date?: number
    }
    opf?: {
      code?: string
      full?: string
      short?: string
    }
    name: {
      full_with_opf?: string
      short_with_opf?: string
      full?: string
      short?: string
    }
    inn: string
    ogrn?: string
    ogrn_date?: number
    okpo?: string
    okato?: string
    oktmo?: string
    okved?: string
    employee_count?: number
    phones?: object[]
    emails?: object[]
    finance?: {
      revenue?: number
      tax_system?: string
    }
    address?: {
      value?: string
      unrestricted_value?: string
      data?: {
        region_with_type?: string
        city_with_type?: string
      }
    }
  }
}

interface DaDataResponse {
  suggestions: DaDataCompany[]
}

export interface OrganizationData {
  inn: string
  kpp?: string
  name: string
  fullName: string
  address: string
  addressFull?: string
  ogrn?: string
  ogrnDate?: Date
  isActive: boolean
  type: 'FULFILLMENT' | 'SELLER'

  // Статус организации
  status?: string
  actualityDate?: Date
  registrationDate?: Date
  liquidationDate?: Date

  // Руководитель
  managementName?: string
  managementPost?: string

  // ОПФ
  opfCode?: string
  opfFull?: string
  opfShort?: string

  // Коды статистики
  okato?: string
  oktmo?: string
  okpo?: string
  okved?: string

  // Контакты
  phones?: object[]
  emails?: object[]

  // Финансовые данные
  employeeCount?: number
  revenue?: bigint
  taxSystem?: string

  rawData: DaDataCompany
}

export class DaDataService {
  private apiKey: string
  private apiUrl: string

  constructor() {
    const apiKey = process.env.DADATA_API_KEY
    const apiUrl = process.env.DADATA_API_URL

    if (!apiKey || !apiUrl) {
      throw new Error('DaData API credentials not configured')
    }
    
    this.apiKey = apiKey
    this.apiUrl = apiUrl
  }

  /**
   * Получает информацию об организации по ИНН с retry логикой
   */
  async getOrganizationByInn(inn: string): Promise<OrganizationData | null> {
    const maxRetries = 3
    const baseDelay = 1000 // 1 секунда

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        console.warn(`🔍 DaData API запрос ИНН ${inn}, попытка ${attempt}/${maxRetries}`)
        
        const response = await axios.post<DaDataResponse>(
          `${this.apiUrl}/findById/party`,
          {
            query: inn,
            count: 1,
          },
          {
            headers: {
              Authorization: `Token ${this.apiKey}`,
              'Content-Type': 'application/json',
              Accept: 'application/json',
            },
            timeout: 15000, // 15 секунд timeout
          },
        )

        if (!response.data?.suggestions?.length) {
          console.warn(`⚠️ DaData: организация с ИНН ${inn} не найдена`)
          return null
        }

        const company = response.data.suggestions[0]
        console.warn(`✅ DaData: данные получены для ИНН ${inn}`, {
          name: company.data.name.short || company.data.name.full,
          status: company.data.state?.status,
        })

        // Определяем тип организации на основе ОПФ
        const organizationType = this.determineOrganizationType(company)

        return {
          inn: company.data.inn,
          kpp: company.data.kpp || undefined,
          name: company.data.name.short || company.data.name.full || 'Название не указано',
          fullName: company.data.name.full_with_opf || '',
          address: company.data.address?.value || '',
          addressFull: company.data.address?.unrestricted_value || undefined,
          ogrn: company.data.ogrn || undefined,
          ogrnDate: this.parseDate(company.data.ogrn_date),

          // Статус организации
          status: company.data.state?.status,
          actualityDate: this.parseDate(company.data.state?.actuality_date),
          registrationDate: this.parseDate(company.data.state?.registration_date),
          liquidationDate: this.parseDate(company.data.state?.liquidation_date),

          // Руководитель
          managementName: company.data.management?.name,
          managementPost: company.data.management?.post,

          // ОПФ
          opfCode: company.data.opf?.code,
          opfFull: company.data.opf?.full,
          opfShort: company.data.opf?.short,

          // Коды статистики
          okato: company.data.okato,
          oktmo: company.data.oktmo,
          okpo: company.data.okpo,
          okved: company.data.okved,

          // Контакты
          phones: company.data.phones || undefined,
          emails: company.data.emails || undefined,

          // Финансовые данные
          employeeCount: company.data.employee_count || undefined,
          revenue: company.data.finance?.revenue ? BigInt(company.data.finance.revenue) : undefined,
          taxSystem: company.data.finance?.tax_system || undefined,

          isActive: company.data.state?.status === 'ACTIVE',
          type: organizationType,
          rawData: company,
        }
      } catch (error) {
        const isLastAttempt = attempt === maxRetries
        const errorMessage = error instanceof Error ? error.message : String(error)
        
        console.error(`❌ DaData API ошибка на попытке ${attempt}/${maxRetries}:`, {
          inn,
          error: errorMessage,
          isLastAttempt,
        })

        if (isLastAttempt) {
          console.error(`🚨 DaData API: все попытки исчерпаны для ИНН ${inn}`)
          return null
        }

        // Exponential backoff: 1s, 2s, 4s
        const delay = baseDelay * Math.pow(2, attempt - 1)
        console.warn(`⏳ DaData API: ожидание ${delay}ms перед следующей попыткой`)
        await new Promise(resolve => setTimeout(resolve, delay))
      }
    }

    return null
  }

  /**
   * Безопасно парсит дату из timestamp, возвращает undefined для некорректных дат
   */
  private parseDate(timestamp?: number): Date | undefined {
    if (!timestamp) return undefined

    try {
      const date = new Date(timestamp * 1000)
      // Проверяем, что дата валидна и разумна (между 1900 и 2100 годами)
      if (isNaN(date.getTime()) || date.getFullYear() < 1900 || date.getFullYear() > 2100) {
        return undefined
      }
      return date
    } catch {
      return undefined
    }
  }

  /**
   * Определяет тип организации на основе ОПФ (организационно-правовая форма)
   */
  private determineOrganizationType(company: DaDataCompany): 'FULFILLMENT' | 'SELLER' {
    const opfCode = company.data.opf?.code

    // Индивидуальные предприниматели чаще работают как селлеры
    if (company.data.type === 'INDIVIDUAL' || opfCode === '50102') {
      return 'SELLER'
    }

    // ООО, АО и другие юридические лица чаще работают с фулфилментом
    return 'FULFILLMENT'
  }

  /**
   * Валидирует ИНН по контрольной сумме
   */
  validateInn(inn: string): boolean {
    const digits = inn.replace(/\D/g, '')

    if (digits.length !== 10 && digits.length !== 12) {
      return false
    }

    // Проверяем контрольную сумму для 10-значного ИНН (юридические лица)
    if (digits.length === 10) {
      const checksum = this.calculateInn10Checksum(digits)
      return checksum === parseInt(digits[9])
    }

    // Проверяем контрольную сумму для 12-значного ИНН (ИП)
    if (digits.length === 12) {
      const checksum1 = this.calculateInn12Checksum1(digits)
      const checksum2 = this.calculateInn12Checksum2(digits)
      return checksum1 === parseInt(digits[10]) && checksum2 === parseInt(digits[11])
    }

    return false
  }

  private calculateInn10Checksum(inn: string): number {
    const weights = [2, 4, 10, 3, 5, 9, 4, 6, 8]
    let sum = 0

    for (let i = 0; i < 9; i++) {
      sum += parseInt(inn[i]) * weights[i]
    }

    return (sum % 11) % 10
  }

  private calculateInn12Checksum1(inn: string): number {
    const weights = [7, 2, 4, 10, 3, 5, 9, 4, 6, 8]
    let sum = 0

    for (let i = 0; i < 10; i++) {
      sum += parseInt(inn[i]) * weights[i]
    }

    return (sum % 11) % 10
  }

  private calculateInn12Checksum2(inn: string): number {
    const weights = [3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8]
    let sum = 0

    for (let i = 0; i < 11; i++) {
      sum += parseInt(inn[i]) * weights[i]
    }

    return (sum % 11) % 10
  }
}
