#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <strings.h>  // for strcasecmp
#include <unistd.h>   // for unlink

#define ORDER_FILE "/srv/http/work_orders_debug.json"
#define MEDIA_DIR "/srv/http/media_debug/"
#define MAX_JSON_SIZE 65536
#define MAX_BOUNDARY 128
#define MAX_NAME 201
#define MAX_COMMENT 3001
#define MAX_ESCAPED_FIELD (MAX_COMMENT * 2)
#define MAX_FILES 10

void escape_json_string(const char *src, char *dest, int maxlen) {
    int i = 0, j = 0;
    while (src[i] && j < maxlen - 1) {
        if (src[i] == '"' || src[i] == '\\') {
            if (j > maxlen - 3) break;
            dest[j++] = '\\';
            dest[j++] = src[i++];
        } else if ((unsigned char)src[i] < 0x20) {
            if (j > maxlen - 7) break;
            sprintf(dest + j, "\\u%04x", src[i++]);
            j += 6;
        } else {
            dest[j++] = src[i++];
        }
    }
    dest[j] = '\0';
}

int extract_field(const char *part, const char *name, char *value, int vsize) {
    char pattern[128];
    snprintf(pattern, sizeof(pattern), "name=\"%s\"", name);
    const char *p = strstr(part, pattern);
    if (!p) return 0;
    p = strstr(p, "\r\n\r\n");
    if (!p) return 0;
    p += 4;
    const char *end = strstr(p, "\r\n--");
    if (!end) end = p + strlen(p);
    int len = end - p;
    if (len >= vsize) len = vsize - 1;
    strncpy(value, p, len);
    value[len] = '\0';
    return 1;
}

int process_files(const char *post_data, int clen, const char *boundary_raw, int id, char media_paths[][256], int *media_count) {
    FILE *log = fopen("/srv/http/add_order_debug.log", "a"); // append log
    if (!log) return 0;

    char boundary[256];
    strncpy(boundary, boundary_raw, sizeof(boundary));
    boundary[sizeof(boundary) - 1] = '\0';


    char *pos = strstr(post_data, boundary);
    int part_index = 0;

    while (pos && *media_count < MAX_FILES) {
        fprintf(log, "\n--- PART %d ---\n", part_index++);
        pos += strlen(boundary);
        if (strncmp(pos, "--", 2) == 0) break;
        pos = strstr(pos, "\r\n");
        if (!pos) break;
        pos += 2;

        char *headers_end = strstr(pos, "\r\n\r\n");
        if (!headers_end) {
            fprintf(log, "No headers end found\n");
            break;
        }

        int headers_len = headers_end - pos;
        char headers[1024];
        if (headers_len >= sizeof(headers)) headers_len = sizeof(headers) - 1;
        strncpy(headers, pos, headers_len);
        headers[headers_len] = '\0';
        fprintf(log, "Headers:\n%s\n", headers);

        if (!strstr(headers, "name=\"media[]\"") || !strstr(headers, "filename=\"")) {
            fprintf(log, "Skipped non-media part\n");
            pos = headers_end + 4;
            pos = strstr(pos, boundary);
            continue;
        }

        char *filename_start = strstr(headers, "filename=\"") + 10;
        char *filename_end = strchr(filename_start, '"');
        if (!filename_start || !filename_end || filename_start == filename_end) {
            fprintf(log, "Invalid filename field\n");
            pos = headers_end + 4;
            pos = strstr(pos, boundary);
            continue;
        }

        char orig_filename[128];
        int flen = filename_end - filename_start;
        if (flen >= sizeof(orig_filename)) flen = sizeof(orig_filename) - 1;
        strncpy(orig_filename, filename_start, flen);
        orig_filename[flen] = '\0';
        fprintf(log, "Original filename: %s\n", orig_filename);

        const char *ext = strrchr(orig_filename, '.');
        if (!ext || strlen(ext) > 10) {
            fprintf(log, "Invalid extension\n");
            pos = headers_end + 4;
            pos = strstr(pos, boundary);
            continue;
        }

        char *data_start = headers_end + 4;

        char search_for[300];
        snprintf(search_for, sizeof(search_for), "%s", boundary);
        fprintf(log, "Looking for part_end using pattern: '%s'\n", search_for);

        // Optional: dump a portion of data_start in hex + ASCII
        int dump_len = 512;
        fprintf(log, "--- Begin dump of data_start (first %d bytes) ---\n", dump_len);
        for (int i = 0; i < dump_len && data_start[i]; i += 16) {
            fprintf(log, "%04x  ", i);
            for (int j = 0; j < 16; j++) {
                if (i + j < dump_len && data_start[i + j]) {
                    fprintf(log, "%02x ", (unsigned char)data_start[i + j]);
                } else {
                    fprintf(log, "   ");
                }
            }
            fprintf(log, " ");
            for (int j = 0; j < 16; j++) {
                if (i + j < dump_len && data_start[i + j]) {
                    char c = data_start[i + j];
                    fprintf(log, "%c", (c >= 32 && c <= 126) ? c : '.');
                }
            }
            fprintf(log, "\n");
        }
        fprintf(log, "--- End dump ---\n");

        // Actual search
        char *part_end = memmem(data_start, clen - (data_start - post_data), boundary, strlen(boundary));

        if (!part_end) {
            fprintf(log, "Could not find part end using '%s'\n", search_for);
            break;
        }

        // Trim trailing CR/LF
        while (part_end > data_start && (part_end[-1] == '\r' || part_end[-1] == '\n'))
            part_end--;


        while (part_end > data_start && (part_end[-1] == '\r' || part_end[-1] == '\n'))
            part_end--;

        long data_len = part_end - data_start;
        if (data_len <= 0) {
            fprintf(log, "Empty file content\n");
            pos = part_end + strlen(boundary);
            continue;
        }

        char stored_filename[256];
        snprintf(stored_filename, sizeof(stored_filename), "%s%d_%d%s", MEDIA_DIR, id, *media_count + 1, ext);

        FILE *mf = fopen(stored_filename, "wb");
        if (!mf) {
            fprintf(log, "Could not open file for writing: %s\n", stored_filename);
            pos = part_end + strlen(boundary);
            continue;
        }

                size_t written = fwrite(data_start, 1, data_len, mf);
        fclose(mf);
        fprintf(log, "Wrote %zu bytes to %s\n", written, stored_filename);

        /* If it's a MOV, transcode to MP4 and use the .mp4 path in JSON */
        const char *public_ext = ext;  // what we will store in JSON
        if (ext && (strcasecmp(ext, ".mov") == 0)) {
            char mp4_filename_fs[256];
            char mp4_filename_web[256];
            snprintf(mp4_filename_fs, sizeof(mp4_filename_fs), "%s%d_%d.mp4", MEDIA_DIR, id, *media_count + 1);
            snprintf(mp4_filename_web, sizeof(mp4_filename_web), "media_debug/%d_%d.mp4", id, *media_count + 1);

            char cmd[1024];
            /* Note: no -vf here to avoid shell-quoting complexity; feel free to add scaling later */
            snprintf(cmd, sizeof(cmd),
                     "ffmpeg -y -i \"%s\" "
                     "-c:v libx264 -preset veryfast -crf 23 "
                     "-pix_fmt yuv420p -profile:v main -level 4.0 "
                     "-movflags +faststart "
                     "-c:a aac -b:a 128k "
                     "\"%s\" >/dev/null 2>&1",
                     stored_filename, mp4_filename_fs);

            int rc = system(cmd);
            if (rc == 0) {
                /* Success: remove original MOV, use MP4 in JSON */
                if (unlink(stored_filename) != 0) {
                    fprintf(log, "Warning: could not unlink original MOV: %s\n", stored_filename);
                }
                snprintf(media_paths[*media_count], 256, "%s", mp4_filename_web);
                public_ext = ".mp4";
                fprintf(log, "Transcode OK -> %s\n", mp4_filename_fs);
            } else {
                /* Failed: keep original MOV in JSON */
                snprintf(media_paths[*media_count], 256, "media_debug/%d_%d%s", id, *media_count + 1, ext);
                fprintf(log, "Transcode FAILED (%d), keeping original: %s\n", rc, stored_filename);
            }
        } else {
            /* Non-MOV: keep as-is */
            snprintf(media_paths[*media_count], 256, "media_debug/%d_%d%s", id, *media_count + 1, ext);
        }

        (*media_count)++;
        pos = strstr(part_end, boundary);

    }

    fclose(log);
    return 1;
}

int main(void) {
    printf("Content-Type: text/plain\r\n\r\n");

    char *ctype = getenv("CONTENT_TYPE");
    char *clen_str = getenv("CONTENT_LENGTH");
    int clen = clen_str ? atoi(clen_str) : 0;
    if (!ctype || clen <= 0 || !strstr(ctype, "multipart/form-data")) {
        printf("Fout: ongeldige aanvraag\n");
        return 1;
    }

    char boundary[MAX_BOUNDARY];
    const char *b = strstr(ctype, "boundary=");
    if (!b) {
        printf("Fout: boundary niet gevonden\n");
        return 1;
    }
    snprintf(boundary, MAX_BOUNDARY, "--%s", b + 9);

    char *post_data = malloc(clen + 1);
    if (!post_data) {
        printf("Fout: geheugen\n");
        return 1;
    }
    fread(post_data, 1, clen, stdin);
    post_data[clen] = '\0';

    FILE *log = fopen("/srv/http/add_order_debug.log", "w");
    if (log) {
        fwrite(post_data, 1, clen, log);
        fclose(log);
    }


    // Extract text fields
    char name[MAX_NAME] = "", comment[MAX_COMMENT] = "", priority[10] = "";
    if (!extract_field(post_data, "name", name, sizeof(name)) ||
        !extract_field(post_data, "comment", comment, sizeof(comment)) ||
        !extract_field(post_data, "priority", priority, sizeof(priority))) {
        printf("Fout: ontbrekende gegevens\n");
        free(post_data);
        return 1;
    }

    char jname[MAX_ESCAPED_FIELD], jcomment[MAX_ESCAPED_FIELD];
    escape_json_string(name, jname, sizeof(jname));
    escape_json_string(comment, jcomment, sizeof(jcomment));

    // Load JSON file
    FILE *fp = fopen(ORDER_FILE, "r+");
    if (!fp) {
        fp = fopen(ORDER_FILE, "w");
        if (!fp) {
            printf("Fout: kan debug JSON bestand niet openen of aanmaken: %s\n", ORDER_FILE);
            free(post_data);
            return 1;
        }
        fprintf(fp, "[]");
        fclose(fp);
        fp = fopen(ORDER_FILE, "r+");
        if (!fp) {
            printf("Fout: kan debug JSON bestand niet heropenen: %s\n", ORDER_FILE);
            free(post_data);
            return 1;
        }
    }

    char json[MAX_JSON_SIZE];
    size_t read = fread(json, 1, sizeof(json) - 1, fp);
    json[read] = '\0';

    // Get new ID
    int id = 1, max_id = 0;
    for (char *s = json; (s = strstr(s, "\"id\"")); s++) {
        int current_id;
        if (sscanf(s, "\"id\": %d", &current_id) == 1 && current_id > max_id)
            max_id = current_id;
    }
    id = max_id + 1;

    // Handle media files
    char media_paths[MAX_FILES][256];
    int media_count = 0;
    process_files(post_data, clen, boundary, id, media_paths, &media_count);

    // Build media array JSON
    char media_json[2048] = "";
    strcat(media_json, "[");
    for (int i = 0; i < media_count; i++) {
        if (i > 0) strcat(media_json, ", ");
        strcat(media_json, "\"");
        strcat(media_json, media_paths[i]);
        strcat(media_json, "\"");
    }
    strcat(media_json, "]");

    // Build new entry
    char new_entry[4096];
    snprintf(new_entry, sizeof(new_entry),
        "  {\n"
        "    \"id\": %d,\n"
        "    \"name\": \"%s\",\n"
        "    \"comment\": \"%s\",\n"
        "    \"priority\": %s,\n"
        "    \"bezig\": false,\n"
        "    \"deleted\": false,\n"
        "    \"media\": %s\n"
        "  }", id, jname, jcomment, priority, media_json);

    // Inject into JSON file
    char *start = strchr(json, '[');
    char *end = strrchr(json, ']');
    if (!start || !end || end <= start) {
        printf("Fout: ongeldige JSON structuur\n");
        fclose(fp);
        free(post_data);
        return 1;
    }

    *end = '\0'; // Temporarily remove closing ]
    fseek(fp, 0, SEEK_SET);
    fprintf(fp, "%s", start);
    if (end - start > 1) fprintf(fp, ",\n");
    fprintf(fp, "%s\n]", new_entry);
    fclose(fp);
    free(post_data);

    printf("OK\n");
    return 0;
}
