ALTER TYPE app.applicant_status ADD VALUE IF NOT EXISTS 'Failed';

ALTER TABLE app.candidate
    ADD COLUMN IF NOT EXISTS status_changed_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
    ADD COLUMN IF NOT EXISTS lifecycle_notifications jsonb DEFAULT '{}'::jsonb NOT NULL,
    ADD COLUMN IF NOT EXISTS analysis_last_run_at timestamp with time zone,
    ADD COLUMN IF NOT EXISTS analysis_input_fingerprint text,
    ADD COLUMN IF NOT EXISTS invalidated_at timestamp with time zone,
    ADD COLUMN IF NOT EXISTS reupload_requested_at timestamp with time zone,
    ADD COLUMN IF NOT EXISTS reuploaded_at timestamp with time zone,
    ADD COLUMN IF NOT EXISTS failed_purged_at timestamp with time zone;

UPDATE app.candidate
SET status_changed_at = CASE
    WHEN status = 'Initial'::app.applicant_status THEN COALESCE(created_at, last_updated_at, CURRENT_TIMESTAMP)
    WHEN status = 'Pending'::app.applicant_status THEN COALESCE(submitted_at, last_updated_at, created_at, CURRENT_TIMESTAMP)
    ELSE COALESCE(last_updated_at, submitted_at, created_at, CURRENT_TIMESTAMP)
END;

CREATE INDEX IF NOT EXISTS idx_candidate_status_changed_at ON app.candidate (status, status_changed_at);
CREATE INDEX IF NOT EXISTS idx_candidate_reupload_flags ON app.candidate (invalidated_at, reuploaded_at);

CREATE OR REPLACE FUNCTION app.handle_candidate_status_lifecycle()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
    IF NEW.status IS DISTINCT FROM OLD.status THEN
        NEW.status_changed_at = CURRENT_TIMESTAMP;

        IF NEW.status = 'Invalid'::app.applicant_status THEN
            NEW.invalidated_at = CURRENT_TIMESTAMP;
            NEW.reuploaded_at = NULL;
        ELSIF OLD.status = 'Invalid'::app.applicant_status
           AND NEW.status = 'Initial'::app.applicant_status THEN
            NEW.reupload_requested_at = CURRENT_TIMESTAMP;
        END IF;
    END IF;

    RETURN NEW;
END;
$$;

DROP TRIGGER IF EXISTS candidate_status_lifecycle_trigger ON app.candidate;
CREATE TRIGGER candidate_status_lifecycle_trigger
BEFORE UPDATE OF status ON app.candidate
FOR EACH ROW
EXECUTE FUNCTION app.handle_candidate_status_lifecycle();

CREATE OR REPLACE FUNCTION app.mark_candidate_reuploaded_after_invalid()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
    IF NEW.uploaded IS TRUE
       AND (OLD.uploaded IS DISTINCT FROM TRUE) THEN
        UPDATE app.candidate
        SET reuploaded_at = CURRENT_TIMESTAMP
        WHERE candidate_id = NEW.candidate_id
          AND invalidated_at IS NOT NULL
          AND status = 'Initial'::app.applicant_status
          AND (reuploaded_at IS NULL OR reuploaded_at < invalidated_at);
    END IF;

    RETURN NEW;
END;
$$;

DROP TRIGGER IF EXISTS candidate_document_reupload_marker_trigger ON app.candidate_document;
CREATE TRIGGER candidate_document_reupload_marker_trigger
AFTER UPDATE OF uploaded ON app.candidate_document
FOR EACH ROW
EXECUTE FUNCTION app.mark_candidate_reuploaded_after_invalid();
