CREATE TABLE IF NOT EXISTS machines (
    id SERIAL PRIMARY KEY,
    code VARCHAR(50) NOT NULL UNIQUE,
    name VARCHAR(120) NOT NULL,
    brand VARCHAR(120),
    model VARCHAR(120),
    status VARCHAR(50) NOT NULL DEFAULT 'hors_planning',
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    powered_on BOOLEAN NOT NULL DEFAULT TRUE,
    cycle_signal_edge VARCHAR(20) NOT NULL DEFAULT 'rising',
    debounce_ms INTEGER NOT NULL DEFAULT 300,
    min_cycle_time_sec INTEGER NOT NULL DEFAULT 5,
    max_cycle_time_sec INTEGER NOT NULL DEFAULT 300,
    stop_detection_delay_sec INTEGER NOT NULL DEFAULT 180,
    last_cycle_at TIMESTAMPTZ,
    status_since TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS production_orders (
    id SERIAL PRIMARY KEY,
    order_number VARCHAR(80) NOT NULL UNIQUE,
    machine_id INTEGER NOT NULL REFERENCES machines(id),
    article_ref VARCHAR(80) NOT NULL,
    article_name VARCHAR(160) NOT NULL,
    mold_ref VARCHAR(80),
    material_ref VARCHAR(80),
    planned_qty INTEGER NOT NULL,
    cavities INTEGER NOT NULL DEFAULT 1,
    theoretical_cycle_time_sec DOUBLE PRECISION NOT NULL,
    status VARCHAR(40) NOT NULL DEFAULT 'planned',
    started_at TIMESTAMPTZ,
    ended_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS downtime_reasons (
    code VARCHAR(80) PRIMARY KEY,
    label VARCHAR(160) NOT NULL
);

CREATE TABLE IF NOT EXISTS scrap_reasons (
    code VARCHAR(80) PRIMARY KEY,
    label VARCHAR(160) NOT NULL
);

CREATE TABLE IF NOT EXISTS operators (
    id SERIAL PRIMARY KEY,
    name VARCHAR(120) NOT NULL UNIQUE,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS machine_events (
    id SERIAL PRIMARY KEY,
    machine_id INTEGER NOT NULL REFERENCES machines(id),
    event_type VARCHAR(80) NOT NULL,
    timestamp TIMESTAMPTZ NOT NULL,
    payload JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS cycles (
    id SERIAL PRIMARY KEY,
    machine_id INTEGER NOT NULL REFERENCES machines(id),
    production_order_id INTEGER REFERENCES production_orders(id),
    timestamp TIMESTAMPTZ NOT NULL,
    cycle_time_sec DOUBLE PRECISION NOT NULL,
    cavities INTEGER NOT NULL DEFAULT 1,
    produced_qty INTEGER NOT NULL DEFAULT 1,
    is_valid BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS downtimes (
    id SERIAL PRIMARY KEY,
    machine_id INTEGER NOT NULL REFERENCES machines(id),
    production_order_id INTEGER REFERENCES production_orders(id),
    start_time TIMESTAMPTZ NOT NULL,
    end_time TIMESTAMPTZ,
    duration_sec INTEGER,
    reason_code VARCHAR(80) REFERENCES downtime_reasons(code),
    comment TEXT,
    auto_detected BOOLEAN NOT NULL DEFAULT TRUE,
    qualified_by VARCHAR(120),
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS scraps (
    id SERIAL PRIMARY KEY,
    machine_id INTEGER NOT NULL REFERENCES machines(id),
    production_order_id INTEGER REFERENCES production_orders(id),
    quantity INTEGER NOT NULL,
    reason_code VARCHAR(80) NOT NULL REFERENCES scrap_reasons(code),
    comment TEXT,
    operator_name VARCHAR(120) NOT NULL,
    timestamp TIMESTAMPTZ NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_machine_events_machine_time ON machine_events(machine_id, timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_cycles_machine_time ON cycles(machine_id, timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_downtimes_machine_time ON downtimes(machine_id, start_time DESC);
CREATE INDEX IF NOT EXISTS idx_scraps_machine_time ON scraps(machine_id, timestamp DESC);
