-- Rename table experiment_phases to experiment_books
-- This migration renames the table and updates all dependent objects (views, functions, triggers, indexes, RLS).

-- =============================================
-- 1. RENAME TABLE
-- =============================================

ALTER TABLE public.experiment_phases RENAME TO experiment_books;

-- =============================================
-- 2. RENAME TRIGGER
-- =============================================

DROP TRIGGER IF EXISTS set_updated_at_experiment_phases ON public.experiment_books;
CREATE TRIGGER set_updated_at_experiment_books
    BEFORE UPDATE ON public.experiment_books
    FOR EACH ROW
    EXECUTE FUNCTION public.handle_updated_at();

-- =============================================
-- 3. RENAME CONSTRAINT
-- =============================================

ALTER TABLE public.experiment_books
    RENAME CONSTRAINT ck_experiment_phases_machine_required_when_cracking
    TO ck_experiment_books_machine_required_when_cracking;

-- =============================================
-- 4. RENAME INDEXES
-- =============================================

ALTER INDEX IF EXISTS public.idx_experiment_phases_name RENAME TO idx_experiment_books_name;
ALTER INDEX IF EXISTS public.idx_experiment_phases_cracking_machine_type_id RENAME TO idx_experiment_books_cracking_machine_type_id;

-- =============================================
-- 5. RLS POLICIES (drop old, create new with updated names)
-- =============================================

DROP POLICY IF EXISTS "Experiment phases are viewable by authenticated users" ON public.experiment_books;
DROP POLICY IF EXISTS "Experiment phases are insertable by authenticated users" ON public.experiment_books;
DROP POLICY IF EXISTS "Experiment phases are updatable by authenticated users" ON public.experiment_books;
DROP POLICY IF EXISTS "Experiment phases are deletable by authenticated users" ON public.experiment_books;

CREATE POLICY "Experiment books are viewable by authenticated users" ON public.experiment_books
    FOR SELECT USING (auth.role() = 'authenticated');

CREATE POLICY "Experiment books are insertable by authenticated users" ON public.experiment_books
    FOR INSERT WITH CHECK (auth.role() = 'authenticated');

CREATE POLICY "Experiment books are updatable by authenticated users" ON public.experiment_books
    FOR UPDATE USING (auth.role() = 'authenticated');

CREATE POLICY "Experiment books are deletable by authenticated users" ON public.experiment_books
    FOR DELETE USING (auth.role() = 'authenticated');

-- =============================================
-- 6. UPDATE FUNCTION: create_phase_executions_for_repetition (references experiment_phases)
-- =============================================

CREATE OR REPLACE FUNCTION create_phase_executions_for_repetition()
RETURNS TRIGGER AS $$
DECLARE
    exp_phase_config RECORD;
    phase_type_list TEXT[] := ARRAY[]::TEXT[];
    phase_name TEXT;
BEGIN
    SELECT 
        ep.has_soaking,
        ep.has_airdrying,
        ep.has_cracking,
        ep.has_shelling,
        ep.cracking_machine_type_id
    INTO exp_phase_config
    FROM public.experiments e
    JOIN public.experiment_books ep ON e.phase_id = ep.id
    WHERE e.id = NEW.experiment_id;
    
    IF exp_phase_config.has_soaking THEN
        phase_type_list := array_append(phase_type_list, 'soaking');
    END IF;
    IF exp_phase_config.has_airdrying THEN
        phase_type_list := array_append(phase_type_list, 'airdrying');
    END IF;
    IF exp_phase_config.has_cracking THEN
        phase_type_list := array_append(phase_type_list, 'cracking');
    END IF;
    IF exp_phase_config.has_shelling THEN
        phase_type_list := array_append(phase_type_list, 'shelling');
    END IF;
    
    FOREACH phase_name IN ARRAY phase_type_list
    LOOP
        INSERT INTO public.experiment_phase_executions (
            repetition_id,
            phase_type,
            scheduled_start_time,
            status,
            created_by,
            soaking_duration_minutes,
            duration_minutes,
            machine_type_id
        )
        VALUES (
            NEW.id,
            phase_name,
            NOW(),
            'pending',
            NEW.created_by,
            NULL,
            NULL,
            CASE WHEN phase_name = 'cracking' 
                 THEN exp_phase_config.cracking_machine_type_id 
                 ELSE NULL END
        );
    END LOOP;
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- =============================================
-- 7. UPDATE FUNCTION: create_sample_experiment_phases (INSERT into experiment_books)
-- =============================================

CREATE OR REPLACE FUNCTION public.create_sample_experiment_phases()
RETURNS VOID AS $$
DECLARE
    jc_cracker_id UUID;
    meyer_cracker_id UUID;
BEGIN
    SELECT id INTO jc_cracker_id FROM public.machine_types WHERE name = 'JC Cracker';
    SELECT id INTO meyer_cracker_id FROM public.machine_types WHERE name = 'Meyer Cracker';
    
    INSERT INTO public.experiment_books (name, description, has_soaking, has_airdrying, has_cracking, has_shelling, cracking_machine_type_id, created_by) VALUES
    ('Full Process - JC Cracker', 'Complete pecan processing with JC Cracker', true, true, true, true, jc_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1)),
    ('Full Process - Meyer Cracker', 'Complete pecan processing with Meyer Cracker', true, true, true, true, meyer_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1)),
    ('Cracking Only - JC Cracker', 'JC Cracker cracking process only', false, false, true, false, jc_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1)),
    ('Cracking Only - Meyer Cracker', 'Meyer Cracker cracking process only', false, false, true, false, meyer_cracker_id, (SELECT id FROM public.user_profiles LIMIT 1))
    ON CONFLICT (name) DO NOTHING;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- =============================================
-- 8. UPDATE VIEWS (from 00014 - experiments_with_phases, repetitions_with_phases, experiments_with_all_reps_and_phases, get_experiment_with_reps_and_phases)
-- =============================================

CREATE OR REPLACE VIEW public.experiments_with_phases AS
SELECT 
    e.id,
    e.experiment_number,
    e.reps_required,
    e.weight_per_repetition_lbs,
    e.results_status,
    e.completion_status,
    e.phase_id,
    e.created_at,
    e.updated_at,
    e.created_by,
    ep.name as phase_name,
    ep.description as phase_description,
    ep.has_soaking,
    ep.has_airdrying,
    ep.has_cracking,
    ep.has_shelling,
    er.id as first_repetition_id,
    er.repetition_number as first_repetition_number,
    soaking_e.id as soaking_id,
    soaking_e.scheduled_start_time as soaking_scheduled_start,
    soaking_e.actual_start_time as soaking_actual_start,
    soaking_e.soaking_duration_minutes,
    soaking_e.scheduled_end_time as soaking_scheduled_end,
    soaking_e.actual_end_time as soaking_actual_end,
    airdrying_e.id as airdrying_id,
    airdrying_e.scheduled_start_time as airdrying_scheduled_start,
    airdrying_e.actual_start_time as airdrying_actual_start,
    airdrying_e.duration_minutes as airdrying_duration,
    airdrying_e.scheduled_end_time as airdrying_scheduled_end,
    airdrying_e.actual_end_time as airdrying_actual_end,
    cracking_e.id as cracking_id,
    cracking_e.scheduled_start_time as cracking_scheduled_start,
    cracking_e.actual_start_time as cracking_actual_start,
    cracking_e.actual_end_time as cracking_actual_end,
    mt.name as machine_type_name,
    shelling_e.id as shelling_id,
    shelling_e.scheduled_start_time as shelling_scheduled_start,
    shelling_e.actual_start_time as shelling_actual_start,
    shelling_e.actual_end_time as shelling_actual_end
FROM public.experiments e
LEFT JOIN public.experiment_books ep ON e.phase_id = ep.id
LEFT JOIN LATERAL (
    SELECT id, repetition_number 
    FROM public.experiment_repetitions 
    WHERE experiment_id = e.id 
    ORDER BY repetition_number 
    LIMIT 1
) er ON true
LEFT JOIN public.experiment_phase_executions soaking_e 
    ON soaking_e.repetition_id = er.id AND soaking_e.phase_type = 'soaking'
LEFT JOIN public.experiment_phase_executions airdrying_e 
    ON airdrying_e.repetition_id = er.id AND airdrying_e.phase_type = 'airdrying'
LEFT JOIN public.experiment_phase_executions cracking_e 
    ON cracking_e.repetition_id = er.id AND cracking_e.phase_type = 'cracking'
LEFT JOIN public.experiment_phase_executions shelling_e 
    ON shelling_e.repetition_id = er.id AND shelling_e.phase_type = 'shelling'
LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id;

CREATE OR REPLACE VIEW public.repetitions_with_phases AS
SELECT 
    er.id,
    er.experiment_id,
    er.repetition_number,
    er.status,
    er.created_at,
    er.updated_at,
    er.created_by,
    e.experiment_number,
    e.phase_id,
    e.weight_per_repetition_lbs,
    ep.name as phase_name,
    ep.has_soaking,
    ep.has_airdrying,
    ep.has_cracking,
    ep.has_shelling,
    soaking_e.scheduled_start_time as soaking_scheduled_start,
    soaking_e.actual_start_time as soaking_actual_start,
    soaking_e.soaking_duration_minutes,
    soaking_e.scheduled_end_time as soaking_scheduled_end,
    soaking_e.actual_end_time as soaking_actual_end,
    airdrying_e.scheduled_start_time as airdrying_scheduled_start,
    airdrying_e.actual_start_time as airdrying_actual_start,
    airdrying_e.duration_minutes as airdrying_duration,
    airdrying_e.scheduled_end_time as airdrying_scheduled_end,
    airdrying_e.actual_end_time as airdrying_actual_end,
    cracking_e.scheduled_start_time as cracking_scheduled_start,
    cracking_e.actual_start_time as cracking_actual_start,
    cracking_e.actual_end_time as cracking_actual_end,
    mt.name as machine_type_name,
    shelling_e.scheduled_start_time as shelling_scheduled_start,
    shelling_e.actual_start_time as shelling_actual_start,
    shelling_e.actual_end_time as shelling_actual_end
FROM public.experiment_repetitions er
JOIN public.experiments e ON er.experiment_id = e.id
LEFT JOIN public.experiment_books ep ON e.phase_id = ep.id
LEFT JOIN public.experiment_phase_executions soaking_e 
    ON er.id = soaking_e.repetition_id AND soaking_e.phase_type = 'soaking'
LEFT JOIN public.experiment_phase_executions airdrying_e 
    ON er.id = airdrying_e.repetition_id AND airdrying_e.phase_type = 'airdrying'
LEFT JOIN public.experiment_phase_executions cracking_e 
    ON er.id = cracking_e.repetition_id AND cracking_e.phase_type = 'cracking'
LEFT JOIN public.experiment_phase_executions shelling_e 
    ON er.id = shelling_e.repetition_id AND shelling_e.phase_type = 'shelling'
LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id;

-- experiments_with_all_reps_and_phases
CREATE OR REPLACE VIEW public.experiments_with_all_reps_and_phases AS
SELECT 
    e.id as experiment_id,
    e.experiment_number,
    e.reps_required,
    e.weight_per_repetition_lbs,
    e.results_status,
    e.completion_status,
    e.phase_id,
    e.created_at as experiment_created_at,
    e.updated_at as experiment_updated_at,
    e.created_by as experiment_created_by,
    ep.name as phase_name,
    ep.description as phase_description,
    ep.has_soaking,
    ep.has_airdrying,
    ep.has_cracking,
    ep.has_shelling,
    ep.cracking_machine_type_id as phase_cracking_machine_type_id,
    er.id as repetition_id,
    er.repetition_number,
    er.status as repetition_status,
    er.scheduled_date,
    er.created_at as repetition_created_at,
    er.updated_at as repetition_updated_at,
    er.created_by as repetition_created_by,
    soaking_e.id as soaking_execution_id,
    soaking_e.scheduled_start_time as soaking_scheduled_start,
    soaking_e.actual_start_time as soaking_actual_start,
    soaking_e.soaking_duration_minutes,
    soaking_e.scheduled_end_time as soaking_scheduled_end,
    soaking_e.actual_end_time as soaking_actual_end,
    soaking_e.status as soaking_status,
    airdrying_e.id as airdrying_execution_id,
    airdrying_e.scheduled_start_time as airdrying_scheduled_start,
    airdrying_e.actual_start_time as airdrying_actual_start,
    airdrying_e.duration_minutes as airdrying_duration_minutes,
    airdrying_e.scheduled_end_time as airdrying_scheduled_end,
    airdrying_e.actual_end_time as airdrying_actual_end,
    airdrying_e.status as airdrying_status,
    cracking_e.id as cracking_execution_id,
    cracking_e.scheduled_start_time as cracking_scheduled_start,
    cracking_e.actual_start_time as cracking_actual_start,
    cracking_e.scheduled_end_time as cracking_scheduled_end,
    cracking_e.actual_end_time as cracking_actual_end,
    cracking_e.machine_type_id as cracking_machine_type_id,
    cracking_e.status as cracking_status,
    mt.name as machine_type_name,
    shelling_e.id as shelling_execution_id,
    shelling_e.scheduled_start_time as shelling_scheduled_start,
    shelling_e.actual_start_time as shelling_actual_start,
    shelling_e.scheduled_end_time as shelling_scheduled_end,
    shelling_e.actual_end_time as shelling_actual_end,
    shelling_e.status as shelling_status
FROM public.experiments e
LEFT JOIN public.experiment_books ep ON e.phase_id = ep.id
LEFT JOIN public.experiment_repetitions er ON er.experiment_id = e.id
LEFT JOIN public.experiment_phase_executions soaking_e 
    ON soaking_e.repetition_id = er.id AND soaking_e.phase_type = 'soaking'
LEFT JOIN public.experiment_phase_executions airdrying_e 
    ON airdrying_e.repetition_id = er.id AND airdrying_e.phase_type = 'airdrying'
LEFT JOIN public.experiment_phase_executions cracking_e 
    ON cracking_e.repetition_id = er.id AND cracking_e.phase_type = 'cracking'
LEFT JOIN public.experiment_phase_executions shelling_e 
    ON shelling_e.repetition_id = er.id AND shelling_e.phase_type = 'shelling'
LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id
ORDER BY e.experiment_number, er.repetition_number;

-- get_experiment_with_reps_and_phases function
CREATE OR REPLACE FUNCTION public.get_experiment_with_reps_and_phases(p_experiment_id UUID)
RETURNS TABLE (
    experiment_id UUID,
    experiment_number INTEGER,
    phase_name TEXT,
    repetitions JSONB
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        e.id,
        e.experiment_number,
        ep.name,
        COALESCE(
            jsonb_agg(
                jsonb_build_object(
                    'repetition_id', er.id,
                    'repetition_number', er.repetition_number,
                    'status', er.status,
                    'scheduled_date', er.scheduled_date,
                    'soaking', jsonb_build_object(
                        'scheduled_start', soaking_e.scheduled_start_time,
                        'actual_start', soaking_e.actual_start_time,
                        'duration_minutes', soaking_e.soaking_duration_minutes,
                        'scheduled_end', soaking_e.scheduled_end_time,
                        'actual_end', soaking_e.actual_end_time,
                        'status', soaking_e.status
                    ),
                    'airdrying', jsonb_build_object(
                        'scheduled_start', airdrying_e.scheduled_start_time,
                        'actual_start', airdrying_e.actual_start_time,
                        'duration_minutes', airdrying_e.duration_minutes,
                        'scheduled_end', airdrying_e.scheduled_end_time,
                        'actual_end', airdrying_e.actual_end_time,
                        'status', airdrying_e.status
                    ),
                    'cracking', jsonb_build_object(
                        'scheduled_start', cracking_e.scheduled_start_time,
                        'actual_start', cracking_e.actual_start_time,
                        'scheduled_end', cracking_e.scheduled_end_time,
                        'actual_end', cracking_e.actual_end_time,
                        'machine_type_id', cracking_e.machine_type_id,
                        'machine_type_name', mt.name,
                        'status', cracking_e.status
                    ),
                    'shelling', jsonb_build_object(
                        'scheduled_start', shelling_e.scheduled_start_time,
                        'actual_start', shelling_e.actual_start_time,
                        'scheduled_end', shelling_e.scheduled_end_time,
                        'actual_end', shelling_e.actual_end_time,
                        'status', shelling_e.status
                    )
                )
                ORDER BY er.repetition_number
            ),
            '[]'::jsonb
        ) as repetitions
    FROM public.experiments e
    LEFT JOIN public.experiment_books ep ON e.phase_id = ep.id
    LEFT JOIN public.experiment_repetitions er ON er.experiment_id = e.id
    LEFT JOIN public.experiment_phase_executions soaking_e 
        ON soaking_e.repetition_id = er.id AND soaking_e.phase_type = 'soaking'
    LEFT JOIN public.experiment_phase_executions airdrying_e 
        ON airdrying_e.repetition_id = er.id AND airdrying_e.phase_type = 'airdrying'
    LEFT JOIN public.experiment_phase_executions cracking_e 
        ON cracking_e.repetition_id = er.id AND cracking_e.phase_type = 'cracking'
    LEFT JOIN public.experiment_phase_executions shelling_e 
        ON shelling_e.repetition_id = er.id AND shelling_e.phase_type = 'shelling'
    LEFT JOIN public.machine_types mt ON cracking_e.machine_type_id = mt.id
    WHERE e.id = p_experiment_id
    GROUP BY e.id, e.experiment_number, ep.name;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

GRANT SELECT ON public.experiments_with_all_reps_and_phases TO authenticated;
GRANT EXECUTE ON FUNCTION public.get_experiment_with_reps_and_phases(UUID) TO authenticated;
