<?php
// =====================================================================
// Contributions API Endpoint
// Handles CRUD Operations for Contributions (Points, Lines, Polygons)
// and Voting. Actions are  determined by the 'action' Parameter in 
// the Request.
//
// Supported Actions:
//   read   — Load approved Contributions
//   create — Insert Contributions
//   update — Update Contributions
//   delete — Delete Contributions
//   vote   — Like or Dislike Contributions
// =====================================================================

require_once __DIR__ . '/db.php';


// ---------------------------------------------------------------------
// Read Action Parameter and Route to correct Handler
// ---------------------------------------------------------------------
$input = get_input();
$action = $input['action'] ?? '';

switch ($action) {
    case 'read':
        handle_read($input);
        break;
    case 'create':
        handle_create($input);
        break;
    case 'update':
        handle_update($input);
        break;
    case 'delete':
        handle_delete($input);
        break;
    case 'vote':
        handle_vote($input);
        break;
    default:
        error_response('Unknown Action. Supported Actions are read, create, update, delete, vote.');
}


// =====================================================================
// Action Handlers
// =====================================================================


// ---------------------------------------------------------------------
// READ: Loads approved Contributions as GeoJSON FeatureCollection
// Required: municipality_id
// Optional: category
// ---------------------------------------------------------------------
function handle_read($input) {
    $pdo = get_db();

    // Validate Input
    $missing = validate_required($input, ['municipality_id']);
    if (!empty($missing)) {
        error_response('Missing Fields: ' . implode(', ', $missing));
    }

    $municipality_id = $input['municipality_id'];

    // Builds SQL Query with Placeholders for prepared Statement
    $sql = "SELECT *, ST_AsGeoJSON(geom) AS geojson 
            FROM contributions 
            WHERE municipality_id = :mid AND status = 'approved'";
    $params = [':mid' => $municipality_id];

    // Optional: Filters by Category
    if (!empty($input['category'])) {
        $sql .= " AND category = :cat";
        $params[':cat'] = $input['category'];
    }

    $sql .= " ORDER BY created_at DESC";

    try {
        // Prepared Statement to prevent SQL Injection
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        // Fetches Results as PHP-Array
        $rows = $stmt->fetchAll();
    } catch (PDOException $e) {
        error_response('Database Error: ' . $e->getMessage(), 500);
    }

    // Builds GeoJSON FeatureCollection
    $features = [];

    foreach ($rows as $row) {
        $geometry = json_decode($row['geojson']);

        // Removes raw Geometry Columns from Properties
        unset($row['geom']);
        unset($row['geojson']);

        $features[] = [
            'type'       => 'Feature',
            'geometry'   => $geometry,
            'properties' => $row
        ];
    }

    $featureCollection = [
        'type'     => 'FeatureCollection',
        'features' => $features
    ];

    json_response($featureCollection);
}


// ---------------------------------------------------------------------
// CREATE: Inserts new Contributions
// Required: municipality_id, geom, geom_type, category, title, author_name
// Optional: description
// ---------------------------------------------------------------------
function handle_create($input) {
    $pdo = get_db();

    // Validates Input
    $missing = validate_required($input, [
        'municipality_id', 'geom', 'geom_type', 'category', 'title', 'author_name'
    ]);
    if (!empty($missing)) {
        error_response('Missing Fields: ' . implode(', ', $missing));
    }

    // Validates Geometry Type
    $valid_geom_types = ['point', 'line', 'polygon'];
    if (!in_array($input['geom_type'], $valid_geom_types)) {
        error_response('Invalid Geometry Type. Must be: ' . implode(', ', $valid_geom_types));
    }

    // Validates GeoJSON
    $geojson = json_decode($input['geom']);
    if (!$geojson || !isset($geojson->type)) {
        error_response('Invalid GeoJSON in Geometry Field.');
    }

    // Prepared SQL Statement
    try {
        $stmt = $pdo->prepare("
            INSERT INTO contributions 
                (municipality_id, geom, geom_type, category, title, description, author_name)
            VALUES 
                (:mid, ST_SetSRID(ST_GeomFromGeoJSON(:geom), 4326), :geom_type, 
                 :category, :title, :description, :author_name)
        ");

        $stmt->execute([
            ':mid'         => $input['municipality_id'],
            ':geom'        => $input['geom'],
            ':geom_type'   => $input['geom_type'],
            ':category'    => $input['category'],
            ':title'       => $input['title'],
            ':description' => $input['description'] ?? '',
            ':author_name' => $input['author_name']
        ]);

        json_response([
            'message'         => 'Contribution created successfully.',
            'contribution_id' => (int) $pdo->lastInsertId()
        ], 201);

    } catch (PDOException $e) {
        error_response('Database Error: ' . $e->getMessage(), 500);
    }
}


// ---------------------------------------------------------------------
// UPDATE: Updates existing Contributions
// Required: contribution_id
// Optional: category, title, description, status
// Provided Fields are updated. Others remain unchanged.
// ---------------------------------------------------------------------
function handle_update($input) {
    $pdo = get_db();

    // Validates Input
    $missing = validate_required($input, ['contribution_id']);
    if (!empty($missing)) {
        error_response('Missing Fields: ' . implode(', ', $missing));
    }

    $contribution_id = $input['contribution_id'];

    // Checks if Contribution exists
    $stmt = $pdo->prepare("SELECT contribution_id FROM contributions WHERE contribution_id = :id");
    $stmt->execute([':id' => $contribution_id]);
    if (!$stmt->fetch()) {
        error_response('Contribution not found.', 404);
    }

    // Builds dynamic SQL Query to only update sent Fields
    $updatable_fields = ['category', 'title', 'description', 'status'];
    $set_clauses = [];
    $params = [':id' => $contribution_id];

    foreach ($updatable_fields as $field) {
        if (isset($input[$field]) && $input[$field] !== '') {
            $set_clauses[] = "$field = :$field";
            $params[":$field"] = $input[$field];
        }
    }

    if (empty($set_clauses)) {
        error_response('No Fields to update. Provide at least one of: ' . implode(', ', $updatable_fields));
    }

    // Validates Status
    if (isset($params[':status'])) {
        $valid_statuses = ['pending', 'approved', 'rejected', 'in_progress', 'done'];
        if (!in_array($params[':status'], $valid_statuses)) {
            error_response('Invalid Status. Must be: ' . implode(', ', $valid_statuses));
        }
    }
    
    // Builds SQL Statement
    $sql = "UPDATE contributions SET " . implode(', ', $set_clauses) . " WHERE contribution_id = :id";

    // Prepared SQL Statement
    try {
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);

        json_response(['message' => 'Contribution updated successfully.']);

    } catch (PDOException $e) {
        error_response('Database Error: ' . $e->getMessage(), 500);
    }
}


// ---------------------------------------------------------------------
// DELETE: Deletes existing Contributions
// Required: contribution_id
// Associated Votes are deleted automatically
// ---------------------------------------------------------------------
function handle_delete($input) {
    $pdo = get_db();

    // Validates Input
    $missing = validate_required($input, ['contribution_id']);
    if (!empty($missing)) {
        error_response('Missing Fields: ' . implode(', ', $missing));
    }

    $contribution_id = $input['contribution_id'];

    // Checks if Contribution exists
    $stmt = $pdo->prepare("SELECT contribution_id FROM contributions WHERE contribution_id = :id");
    $stmt->execute([':id' => $contribution_id]);
    if (!$stmt->fetch()) {
        error_response('Contribution not found.', 404);
    }

    // Prepared SQL Statement
    try {
        $stmt = $pdo->prepare("DELETE FROM contributions WHERE contribution_id = :id");
        $stmt->execute([':id' => $contribution_id]);

        json_response(['message' => 'Contribution deleted successfully.']);

    } catch (PDOException $e) {
        error_response('Database Error: ' . $e->getMessage(), 500);
    }
}


// ---------------------------------------------------------------------
// VOTE: Likes or Dislikes a Contribution
// Required: contribution_id, voter_name, vote_type
// Database Trigger automatically updates Likes and Dislikes Count
// UNIQUE Constraint prevents duplicate Votes per Voter.
// ---------------------------------------------------------------------
function handle_vote($input) {
    $pdo = get_db();

    // Validates Input
    $missing = validate_required($input, ['contribution_id', 'voter_name', 'vote_type']);
    if (!empty($missing)) {
        error_response('Missing Fields: ' . implode(', ', $missing));
    }

    // Validates Vote Type
    $valid_vote_types = ['like', 'dislike'];
    if (!in_array($input['vote_type'], $valid_vote_types)) {
        error_response('Invalid vote_type. Must be: ' . implode(', ', $valid_vote_types));
    }

    // Checks if Contribution exists
    $stmt = $pdo->prepare("SELECT contribution_id FROM contributions WHERE contribution_id = :id");
    $stmt->execute([':id' => $input['contribution_id']]);
    if (!$stmt->fetch()) {
        error_response('Contribution not found.', 404);
    }

    // Prepared SQL Statement
    try {
        $stmt = $pdo->prepare("
            INSERT INTO votes (contribution_id, voter_name, vote_type)
            VALUES (:cid, :voter, :vtype)
        ");

        $stmt->execute([
            ':cid'   => $input['contribution_id'],
            ':voter' => $input['voter_name'],
            ':vtype' => $input['vote_type']
        ]);

        json_response(['message' => 'Vote recorded successfully.'], 201);

    } catch (PDOException $e) {
        // UNIQUE Constraint Violation - Voter already voted on this Contribution
        if ($e->getCode() == '23505') {
            error_response('You have already voted on this Contribution.', 409);
        }
        error_response('Database Error: ' . $e->getMessage(), 500);
    }
}