#pragma once

#include "utils/using.hpp"
#include "utils/cvec/cvec.hpp"
#include "rdft.hpp"

#include <hack/logger/logger.hpp>

namespace hr
{
  struct fft
  {
    uint_t m_win_size;        
    uint_t m_fft_size;        
    fvec_t m_w;               
    ivec_t m_ip;              
    fvec_t m_complex_spectr;  

    void init(size_t size) noexcept
    {
      m_win_size = size;
      m_fft_size = m_win_size / 2 + 1;
      m_complex_spectr.resize(m_win_size, 0.0);
      m_ip.resize(m_fft_size, 0);
      m_w.resize(m_fft_size, 0.0);
    }

    cvec_t process(fvec_t& in)
    {
      m_complex_spectr = get_complex_spectr(in);

      // Подготавливаем результат: векторы для фазы и амплитуды
      cvec_t res;
      res.m_phas.resize(m_fft_size, 0.0);  // Фаза в радианах для каждой частотной компоненты
      res.m_norm.resize(m_fft_size, 0.0);  // Амплитуда (магнитуда) для каждой частотной компоненты

      // ===========================================================================
      // ВЫЧИСЛЕНИЕ ФАЗЫ:
      // Для постоянной составляющей (0 Гц): фаза может быть 0 или π в зависимости от знака
      if (m_complex_spectr[0] < 0.0) 
        res.m_phas[0] = std::numbers::pi;  // Отрицательное значение → фаза 180°
      else 
        res.m_phas[0] = 0.0;               // Положительное значение → фаза 0°

      // Для основных частот (от 1 до N/2-1): вычисляем фазу через арктангенс
      for (size_t i = 1; i < m_fft_size - 1; ++i) 
      {
        // atan2(Im, Re) дает правильную фазу с учетом квадрантов
        // m_complex_spectr[m_win_size - i] - мнимая часть
        // m_complex_spectr[i] - действительная часть
        res.m_phas[i] = std::atan2f(m_complex_spectr[m_win_size - i], m_complex_spectr[i]);
      }

      // Для частоты Найквиста (N/2): аналогично постоянной составляющей
      if (m_complex_spectr[m_fft_size / 2] < 0) 
        // res.m_phas[m_fft_size - 1] = std::numbers::pi;  // Отрицательное значение → фаза 180°
        res.m_phas[m_fft_size - 1] = 3.14159265358979323846;
      else 
        res.m_phas[m_fft_size - 1] = 0.0;               // Положительное значение → фаза 0°

      // ===========================================================================
      // ВЫЧИСЛЕНИЕ АМПЛИТУДЫ (МАГНИТУДЫ):
      // Для постоянной составляющей (0 Гц): просто абсолютное значение
      res.m_norm[0] = std::fabsf(m_complex_spectr[0]);

      // Для основных частот (от 1 до N/2-1): вычисляем магнитуду как sqrt(Re² + Im²)
      for (size_t i = 1; i < m_fft_size - 1; ++i) 
        // Теорема Пифагора для комплексных чисел
        // закоментированные ниже не дают точность по сравнению с аубио
        // res.m_norm[i] = std::hypotf(m_complex_spectr[i], m_complex_spectr[m_complex_spectr.size() - i]);
        // res.m_norm[i] = std::sqrtf(std::pow(m_complex_spectr[i], 2)+ std::pow(m_complex_spectr[m_complex_spectr.size() - i], 2));
        res.m_norm[i] = std::sqrtf(m_complex_spectr[i] * m_complex_spectr[i] + m_complex_spectr[m_complex_spectr.size() - i] * m_complex_spectr[m_complex_spectr.size() - i]);


      // Для частоты Найквиста (N/2): просто абсолютное значение
      res.m_norm[res.m_norm.size() - 1] = std::fabs(m_complex_spectr[m_complex_spectr.size() / 2]);

      return res;
    }

    fvec_t get_complex_spectr(fvec_t& in)
    {
      fvec_t complex_spectr(m_win_size, 0.0);

      // Выполняем прямое вещественное БПФ
      // Результат сохраняется в том же массиве 'in' в специальном формате
      rdft(m_win_size, in.data(), m_ip.data(), m_w.data());

      // ПРЕОБРАЗОВАНИЕ: конвертируем упакованный формат БПФ в полноценный комплексный спектр
      // Формат после rdft(): 
      // in[0] = Re[0]        // Постоянная составляющая (0 Гц)
      // in[1] = Re[N/2]      // Частота Найквиста (f_sample/2)
      // in[2] = Re[1]        // Действительная часть 1-й частоты
      // in[3] = Im[1]        // Мнимая часть 1-й частоты  
      // in[4] = Re[2]        // Действительная часть 2-й частоты
      // in[5] = Im[2]        // Мнимая часть 2-й частоты
      // in[6] = Re[3]        // Действительная часть 3-й частоты
      // in[7] = Im[3]        // Мнимая часть 3-й частоты
      // ...
      // in[N-2] = Re[N/2-1]  // Действительная часть (N/2-1)-й частоты
      // in[N-1] = Im[N/2-1]  // Мнимая часть (N/2-1)-й частоты
      
      complex_spectr[0] = in[0];  // Постоянная составляющая (0 Гц) - только действительная часть
      complex_spectr[m_win_size / 2] = in[1];  // Частота Найквиста (f_sample/2) - только действительная часть
      
      // Заполняем комплексный спектр для частот от 1 до N/2-1
      for (size_t i = 1; i < m_fft_size - 1; ++i) 
      {
        complex_spectr[i] = in[2 * i];                    // Действительная часть i-й частоты
        complex_spectr[m_win_size - i] = -in[2 * i + 1];  // Мнимая часть i-й частоты (знак изменен для правильной фазы)
      }

      return complex_spectr;
    }
  };
}
