-- =============================================================================
-- Deploys only the POST /api/dc/projects/:project_id/complete handler.
-- Uses CLOB construction to avoid SQLcl bind-variable pre-processing of
-- :status_code / :body / :project_id inside the handler source string.
-- =============================================================================
DECLARE
  v_src CLOB;

  PROCEDURE a(p IN VARCHAR2) IS
  BEGIN DBMS_LOB.APPEND(v_src, TO_CLOB(p)); END;

BEGIN
  DBMS_LOB.CREATETEMPORARY(v_src, TRUE);

  a('      DECLARE');
  a(CHR(10)||'        v_status      dc_projects.status%TYPE;');
  a(CHR(10)||'        v_now         DATE := SYSDATE;');
  a(CHR(10)||'        v_report_md   CLOB;');
  a(CHR(10)||'        v_doc_pdfs    JSON_ARRAY_T;');
  a(CHR(10));
  a(CHR(10)||'        FUNCTION body_to_clob(p_blob IN BLOB) RETURN CLOB IS');
  a(CHR(10)||'          v_clob    CLOB;');
  a(CHR(10)||'          v_dest    INTEGER := 1;');
  a(CHR(10)||'          v_src     INTEGER := 1;');
  a(CHR(10)||'          v_lang    INTEGER := DBMS_LOB.DEFAULT_LANG_CTX;');
  a(CHR(10)||'          v_warning INTEGER;');
  a(CHR(10)||'        BEGIN');
  a(CHR(10)||'          IF p_blob IS NULL OR DBMS_LOB.GETLENGTH(p_blob) = 0 THEN RETURN NULL; END IF;');
  a(CHR(10)||'          DBMS_LOB.CREATETEMPORARY(v_clob, TRUE);');
  a(CHR(10)||'          DBMS_LOB.CONVERTTOCLOB(v_clob, p_blob, DBMS_LOB.LOBMAXSIZE,');
  a(CHR(10)||'                                 v_dest, v_src, NLS_CHARSET_ID(''AL32UTF8''), v_lang, v_warning);');
  a(CHR(10)||'          RETURN v_clob;');
  a(CHR(10)||'        END body_to_clob;');
  a(CHR(10));
  a(CHR(10)||'        FUNCTION base64_to_blob(p_b64 IN CLOB) RETURN BLOB IS');
  a(CHR(10)||'          v_blob   BLOB;');
  a(CHR(10)||'          v_raw    RAW(32767);');
  a(CHR(10)||'          v_len    INTEGER;');
  a(CHR(10)||'          v_chunk  INTEGER := 24000;');
  a(CHR(10)||'          v_offset INTEGER := 1;');
  a(CHR(10)||'          v_sub    VARCHAR2(32767);');
  a(CHR(10)||'        BEGIN');
  a(CHR(10)||'          DBMS_LOB.CREATETEMPORARY(v_blob, TRUE);');
  a(CHR(10)||'          v_len := DBMS_LOB.GETLENGTH(p_b64);');
  a(CHR(10)||'          WHILE v_offset <= v_len LOOP');
  a(CHR(10)||'            v_sub := DBMS_LOB.SUBSTR(p_b64, v_chunk, v_offset);');
  a(CHR(10)||'            v_raw := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(v_sub));');
  a(CHR(10)||'            DBMS_LOB.WRITEAPPEND(v_blob, UTL_RAW.LENGTH(v_raw), v_raw);');
  a(CHR(10)||'            v_offset := v_offset + v_chunk;');
  a(CHR(10)||'          END LOOP;');
  a(CHR(10)||'          RETURN v_blob;');
  a(CHR(10)||'        END base64_to_blob;');
  a(CHR(10));
  a(CHR(10)||'      BEGIN');
  a(CHR(10)||'        DECLARE');
  a(CHR(10)||'          v_body_clob CLOB;');
  a(CHR(10)||'          v_json      JSON_OBJECT_T;');
  a(CHR(10)||'        BEGIN');
  -- Use concatenation to embed the bind variable names so SQLcl doesn't pre-process them
  a(CHR(10)||'          v_body_clob := body_to_clob(' || CHR(58) || 'body);');
  a(CHR(10)||'          IF v_body_clob IS NOT NULL THEN');
  a(CHR(10)||'            v_json      := JSON_OBJECT_T.parse(v_body_clob);');
  a(CHR(10)||'            v_report_md := v_json.get_clob(''report_markdown'');');
  a(CHR(10)||'            BEGIN');
  a(CHR(10)||'              v_doc_pdfs := v_json.get_array(''document_pdfs'');');
  a(CHR(10)||'            EXCEPTION WHEN OTHERS THEN v_doc_pdfs := NULL; END;');
  a(CHR(10)||'            DBMS_LOB.FREETEMPORARY(v_body_clob);');
  a(CHR(10)||'          END IF;');
  a(CHR(10)||'        EXCEPTION WHEN OTHERS THEN NULL;');
  a(CHR(10)||'        END;');
  a(CHR(10));
  a(CHR(10)||'        SELECT status');
  a(CHR(10)||'        INTO   v_status');
  a(CHR(10)||'        FROM   dc_projects');
  a(CHR(10)||'        WHERE  id = ' || CHR(58) || 'project_id');
  a(CHR(10)||'        FOR UPDATE NOWAIT;');
  a(CHR(10));
  a(CHR(10)||'        IF v_status = ''COMPLETED'' THEN');
  a(CHR(10)||'          ' || CHR(58) || 'status_code := 409;');
  a(CHR(10)||'          HTP.P(''{"error":"Projekt ist bereits COMPLETED","project_id":'' || ' || CHR(58) || 'project_id || ''}'');');
  a(CHR(10)||'          RETURN;');
  a(CHR(10)||'        END IF;');
  a(CHR(10));
  a(CHR(10)||'        UPDATE dc_projects');
  a(CHR(10)||'        SET    status                   = ''COMPLETED'',');
  a(CHR(10)||'               completed_at            = v_now,');
  a(CHR(10)||'               progress                = 100,');
  a(CHR(10)||'               current_phase           = ''COMPLETED'',');
  a(CHR(10)||'               current_doc_id          = NULL,');
  a(CHR(10)||'               current_question_id     = NULL,');
  a(CHR(10)||'               estimated_completion_at = NULL');
  a(CHR(10)||'        WHERE  id = ' || CHR(58) || 'project_id;');
  a(CHR(10));
  a(CHR(10)||'        IF v_report_md IS NOT NULL AND DBMS_LOB.GETLENGTH(v_report_md) > 0 THEN');
  a(CHR(10)||'          UPDATE dc_projects SET report_markdown = v_report_md WHERE id = ' || CHR(58) || 'project_id;');
  a(CHR(10));
  a(CHR(10)||'          BEGIN');
  a(CHR(10)||'            DECLARE');
  a(CHR(10)||'              v_email    dc_projects.notification_email%TYPE;');
  a(CHR(10)||'              v_name     dc_projects.name%TYPE;');
  a(CHR(10)||'              v_done     dc_projects.completed_at%TYPE;');
  a(CHR(10)||'              v_mail_id  NUMBER;');
  a(CHR(10)||'              v_ok_cnt   NUMBER := 0;');
  a(CHR(10)||'              v_warn_cnt NUMBER := 0;');
  a(CHR(10)||'              v_dev_cnt  NUMBER := 0;');
  a(CHR(10)||'              v_total    NUMBER := 0;');
  a(CHR(10)||'              C_OK   CONSTANT VARCHAR2(10 CHAR) := UNISTR(''\2705'');');
  a(CHR(10)||'              C_NOK  CONSTANT VARCHAR2(10 CHAR) := UNISTR(''\274C'');');
  a(CHR(10)||'              C_WARN CONSTANT VARCHAR2(10 CHAR) := UNISTR(''\26A0\FE0F'');');
  a(CHR(10)||'              CRLF   CONSTANT VARCHAR2(2)       := CHR(13)||CHR(10);');
  a(CHR(10)||'              v_body     VARCHAR2(4000);');
  a(CHR(10)||'              v_doc_obj  JSON_OBJECT_T;');
  a(CHR(10)||'              v_pdf_b64  CLOB;');
  a(CHR(10)||'              v_pdf_blob BLOB;');
  a(CHR(10)||'              v_fname    VARCHAR2(500);');
  a(CHR(10)||'            BEGIN');
  a(CHR(10)||'              SELECT notification_email, name, completed_at');
  a(CHR(10)||'              INTO   v_email, v_name, v_done');
  a(CHR(10)||'              FROM   dc_projects WHERE id = ' || CHR(58) || 'project_id;');
  a(CHR(10));
  a(CHR(10)||'              IF v_email IS NOT NULL AND TRIM(v_email) IS NOT NULL THEN');
  a(CHR(10)||'                SELECT COUNT(*),');
  a(CHR(10)||'                       SUM(CASE WHEN deviation = 1                   THEN 1 ELSE 0 END),');
  a(CHR(10)||'                       SUM(CASE WHEN warning   = 1 AND deviation = 0 THEN 1 ELSE 0 END)');
  a(CHR(10)||'                INTO   v_total, v_dev_cnt, v_warn_cnt');
  a(CHR(10)||'                FROM   dc_results WHERE project_id = ' || CHR(58) || 'project_id;');
  a(CHR(10)||'                v_ok_cnt := v_total - v_dev_cnt - v_warn_cnt;');
  a(CHR(10));
  a(CHR(10)||'                v_body :=');
  a(CHR(10)||'                  ''Sehr geehrte Damen und Herren,'' || CRLF ||');
  a(CHR(10)||'                  CRLF ||');
  a(CHR(10)||'                  ''die automatische Dokumentenprüfung für das Projekt'' || CRLF ||');
  a(CHR(10)||'                  ''„'' || v_name || ''"'' || CRLF ||');
  a(CHR(10)||'                  ''wurde am '' || TO_CHAR(NVL(v_done, SYSDATE), ''DD.MM.YYYY'') ||');
  a(CHR(10)||'                  '' erfolgreich abgeschlossen.'' || CRLF ||');
  a(CHR(10)||'                  CRLF ||');
  a(CHR(10)||'                  ''Zusammenfassung der Prüfergebnisse:'' || CRLF ||');
  a(CHR(10)||'                  C_OK   || ''  OK:              '' || v_ok_cnt   || CRLF ||');
  a(CHR(10)||'                  C_WARN || ''  Hinweise:        '' || v_warn_cnt || CRLF ||');
  a(CHR(10)||'                  C_NOK  || ''  Abweichungen:    '' || v_dev_cnt  || CRLF ||');
  a(CHR(10)||'                  ''    Gesamt:         '' || v_total || '' Prüfpunkte'' || CRLF ||');
  a(CHR(10)||'                  CRLF ||');
  a(CHR(10)||'                  ''Die Prüfberichte der einzelnen Dokumente finden Sie als PDF-Anhänge.'' || CRLF ||');
  a(CHR(10)||'                  CRLF ||');
  a(CHR(10)||'                  ''Mit freundlichen Grüßen'' || CRLF ||');
  a(CHR(10)||'                  ''Ihr Dokumenten-Check-System'' || CRLF ||');
  a(CHR(10)||'                  ''Frigosped Express GmbH'';');
  a(CHR(10));
  a(CHR(10)||'                v_mail_id := APEX_MAIL.SEND(');
  a(CHR(10)||'                  p_to   => v_email,');
  a(CHR(10)||'                  p_from => DC_UTILS_PKG.c_mail_from,');
  a(CHR(10)||'                  p_subj => ''Prüfbericht: '' || v_name,');
  a(CHR(10)||'                  p_body => v_body');
  a(CHR(10)||'                );');
  a(CHR(10));
  a(CHR(10)||'                IF v_doc_pdfs IS NOT NULL AND v_doc_pdfs.get_size > 0 THEN');
  a(CHR(10)||'                  FOR i IN 0 .. v_doc_pdfs.get_size - 1 LOOP');
  a(CHR(10)||'                    BEGIN');
  a(CHR(10)||'                      v_doc_obj  := TREAT(v_doc_pdfs.get(i) AS JSON_OBJECT_T);');
  a(CHR(10)||'                      v_fname    := v_doc_obj.get_string(''filename'');');
  a(CHR(10)||'                      v_pdf_b64  := v_doc_obj.get_clob(''pdf_base64'');');
  a(CHR(10)||'                      IF v_pdf_b64 IS NOT NULL AND DBMS_LOB.GETLENGTH(v_pdf_b64) > 0 THEN');
  a(CHR(10)||'                        v_pdf_blob := base64_to_blob(v_pdf_b64);');
  a(CHR(10)||'                        APEX_MAIL.ADD_ATTACHMENT(');
  a(CHR(10)||'                          p_mail_id    => v_mail_id,');
  a(CHR(10)||'                          p_attachment => v_pdf_blob,');
  a(CHR(10)||'                          p_filename   => NVL(v_fname, ''Pruefbericht.pdf''),');
  a(CHR(10)||'                          p_mime_type  => ''application/pdf''');
  a(CHR(10)||'                        );');
  a(CHR(10)||'                        DBMS_LOB.FREETEMPORARY(v_pdf_blob);');
  a(CHR(10)||'                        DBMS_LOB.FREETEMPORARY(v_pdf_b64);');
  a(CHR(10)||'                      END IF;');
  a(CHR(10)||'                    EXCEPTION WHEN OTHERS THEN NULL;');
  a(CHR(10)||'                    END;');
  a(CHR(10)||'                  END LOOP;');
  a(CHR(10)||'                END IF;');
  a(CHR(10)||'              END IF;');
  a(CHR(10)||'            EXCEPTION WHEN OTHERS THEN NULL;');
  a(CHR(10)||'            END;');
  a(CHR(10)||'          END;');
  a(CHR(10)||'        ELSE');
  a(CHR(10)||'          BEGIN');
  a(CHR(10)||'            DC_UTILS_PKG.generate_report(' || CHR(58) || 'project_id);');
  a(CHR(10)||'          EXCEPTION WHEN OTHERS THEN NULL;');
  a(CHR(10)||'          END;');
  a(CHR(10)||'        END IF;');
  a(CHR(10));
  a(CHR(10)||'        ' || CHR(58) || 'status_code := 200;');
  a(CHR(10)||'        HTP.P(''{"project_id":'' || ' || CHR(58) || 'project_id');
  a(CHR(10)||'           || '',\"status\":\"COMPLETED\"''');
  a(CHR(10)||'           || '',\"completed_at\":\"'' || TO_CHAR(v_now, ''YYYY-MM-DD"T"HH24:MI:SS'') || ''\"''');
  a(CHR(10)||'           || ''}'');');
  a(CHR(10));
  a(CHR(10)||'      EXCEPTION');
  a(CHR(10)||'        WHEN NO_DATA_FOUND THEN');
  a(CHR(10)||'          ' || CHR(58) || 'status_code := 404;');
  a(CHR(10)||'          HTP.P(''{"error":"Projekt nicht gefunden","project_id":'' || ' || CHR(58) || 'project_id || ''}'');');
  a(CHR(10)||'        WHEN OTHERS THEN');
  a(CHR(10)||'          ROLLBACK;');
  a(CHR(10)||'          ' || CHR(58) || 'status_code := 500;');
  a(CHR(10)||'          HTP.P(''{"error":"'' || REPLACE(SQLERRM, ''"'', '''''''') || ''"}'');');
  a(CHR(10)||'      END;');

  ORDS.DEFINE_HANDLER(
    p_module_name => 'frigosped.dc',
    p_pattern     => 'projects/:project_id/complete',
    p_method      => 'POST',
    p_source_type => ORDS.SOURCE_TYPE_PLSQL,
    p_comments    => 'Setzt status=COMPLETED, sendet pro Dokument ein PDF per E-Mail',
    p_source      => v_src
  );

  DBMS_LOB.FREETEMPORARY(v_src);
  COMMIT;
  DBMS_OUTPUT.PUT_LINE('Handler erfolgreich deployed.');
END;
/
