#pragma once
#include <vector>
#include <unordered_map>
#include "schneide_base/Interval.hpp"
#include "schneide_base/Line.hpp"
#include "schneide_base/Vocabulary.hpp"

namespace vera
{
using Interval = schneide::Interval;
using Line = schneide::Line;

class Spectrum
{
public:
  Spectrum();
  Spectrum(Spectrum&&) = default;
  Spectrum(Spectrum const&) = default;
  Spectrum(Interval wavenumbers, std::vector<double> intensities);
  Spectrum(Line line, std::size_t N);
  ~Spectrum();

  Spectrum& operator=(Spectrum const& spectrum) = default;
  Spectrum& operator=(Spectrum&& spectrum) = default;

  Interval wavenumbers() const;
  Interval& wavenumbers();

  std::vector<double> const& intensities() const;
  std::vector<double>& intensities();

  void saveCSV(std::string const& filename) const;
  void saveTaggedCSV(
    std::string const& experimentTag, std::string const& typeTag) const;

  double at(double wavenumber) const;

  /** Unclamped and unrounded index for the wavenumber
  */
  double index(double wavenumber) const;

  double wavenumberAt(std::size_t index) const;

  std::size_t clampedIndex(long unclamped) const;

  std::size_t indexCeil(double wavenumber) const;
  std::size_t indexFloor(double wavenumber) const;

  double binWidth() const;
  std::size_t binCount() const;

private:
  // Wavenumber (maybe just use a range here?)
  Interval mWavenumbers;
  // Intensity
  std::vector<double> mIntensities;
};

Spectrum logOrZero(Spectrum spectrum);
Spectrum operator-(Spectrum lhs, Spectrum const& rhs);
Spectrum operator/(Spectrum lhs, Spectrum const& rhs);
Spectrum operator-(Spectrum lhs);

Spectrum gauss(Spectrum spectrum, double sigmaWaveNumber);
void saveTaggedCSVFor(std::vector<std::pair<std::string, Ptr<Spectrum>>> spectrums,
  std::string const& experimentTag, std::string const& typeTag);

std::unordered_map<std::string, Ptr<Spectrum>> loadSpectrums(std::string const& filename);

struct PeakInfo
{
  static PeakInfo computeFrom(Spectrum const& spectrum, double peakPosition, double searchWidth, double isolation);
  double relativePeak() const;

  double peakWavenumber;
  double peakIntensity;
  Line baseLine;
};


}  // namespace vera
