// shape.cpp - Implementació del sistema de formes vectorials
// © 2025 Port a C++20 amb SDL3

#include "core/graphics/shape.hpp"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>

namespace Graphics {

Shape::Shape(const std::string& filepath)
    : centre_({.x = 0.0F, .y = 0.0F}),
      escala_defecte_(1.0F),
      nom_("unnamed") {
    carregar(filepath);
}

bool Shape::carregar(const std::string& filepath) {
    // Llegir fitxer
    std::ifstream file(filepath);
    if (!file.is_open()) {
        std::cerr << "[Shape] Error: no es pot obrir " << filepath << std::endl;
        return false;
    }

    // Llegir tot el contingut
    std::stringstream buffer;
    buffer << file.rdbuf();
    std::string contingut = buffer.str();
    file.close();

    // Parsejar
    return parsejar_fitxer(contingut);
}

bool Shape::parsejar_fitxer(const std::string& contingut) {
    std::istringstream iss(contingut);
    std::string line;

    while (std::getline(iss, line)) {
        // Trim whitespace
        line = trim(line);

        // Skip comments and blanks
        if (line.empty() || line[0] == '#') {
            continue;
        }

        // Parse command
        if (starts_with(line, "name:")) {
            nom_ = trim(extract_value(line));
        } else if (starts_with(line, "scale:")) {
            try {
                escala_defecte_ = std::stof(extract_value(line));
            } catch (...) {
                std::cerr << "[Shape] Warning: escala invàlida, usant 1.0" << std::endl;
                escala_defecte_ = 1.0F;
            }
        } else if (starts_with(line, "center:")) {
            parse_center(extract_value(line));
        } else if (starts_with(line, "polyline:")) {
            auto points = parse_points(extract_value(line));
            if (points.size() >= 2) {
                primitives_.push_back({PrimitiveType::POLYLINE, points});
            } else {
                std::cerr << "[Shape] Warning: polyline amb menys de 2 punts ignorada"
                          << std::endl;
            }
        } else if (starts_with(line, "line:")) {
            auto points = parse_points(extract_value(line));
            if (points.size() == 2) {
                primitives_.push_back({PrimitiveType::LINE, points});
            } else {
                std::cerr << "[Shape] Warning: line ha de tenir exactament 2 punts"
                          << std::endl;
            }
        }
        // Comandes desconegudes ignorades silenciosament
    }

    if (primitives_.empty()) {
        std::cerr << "[Shape] Error: cap primitiva carregada" << std::endl;
        return false;
    }

    return true;
}

// Helper: trim whitespace
std::string Shape::trim(const std::string& str) const {
    const char* whitespace = " \t\n\r";
    size_t start = str.find_first_not_of(whitespace);
    if (start == std::string::npos) {
        return "";
    }

    size_t end = str.find_last_not_of(whitespace);
    return str.substr(start, end - start + 1);
}

// Helper: starts_with
bool Shape::starts_with(const std::string& str,
    const std::string& prefix) const {
    if (str.length() < prefix.length()) {
        return false;
    }
    return str.starts_with(prefix);
}

// Helper: extract value after ':'
std::string Shape::extract_value(const std::string& line) const {
    size_t colon = line.find(':');
    if (colon == std::string::npos) {
        return "";
    }
    return line.substr(colon + 1);
}

// Helper: parse center "x, y"
void Shape::parse_center(const std::string& value) {
    std::string val = trim(value);
    size_t comma = val.find(',');
    if (comma != std::string::npos) {
        try {
            centre_.x = std::stof(trim(val.substr(0, comma)));
            centre_.y = std::stof(trim(val.substr(comma + 1)));
        } catch (...) {
            std::cerr << "[Shape] Warning: centre invàlid, usant (0,0)" << std::endl;
            centre_ = {.x = 0.0F, .y = 0.0F};
        }
    }
}

// Helper: parse points "x1,y1  x2,y2  x3,y3"
std::vector<Punt> Shape::parse_points(const std::string& str) const {
    std::vector<Punt> points;
    std::istringstream iss(trim(str));
    std::string pair;

    while (iss >> pair) {  // Whitespace-separated
        size_t comma = pair.find(',');
        if (comma != std::string::npos) {
            try {
                float x = std::stof(pair.substr(0, comma));
                float y = std::stof(pair.substr(comma + 1));
                points.push_back({x, y});
            } catch (...) {
                std::cerr << "[Shape] Warning: punt invàlid ignorat: " << pair
                          << std::endl;
            }
        }
    }

    return points;
}

}  // namespace Graphics
