-- 1) Schema changes
ALTER TABLE departments
    ADD COLUMN parent_department_id UUID REFERENCES departments(id) ON DELETE CASCADE;

CREATE INDEX idx_departments_parent_id ON departments(parent_department_id);

-- (Optional but recommended for ltree lookups)
-- CREATE EXTENSION IF NOT EXISTS ltree;
-- CREATE INDEX idx_departments_path_gist ON departments USING GIST (path);
-- CREATE INDEX idx_departments_path_nlevel ON departments ((nlevel(path)));

-- 2) Migrate parent ids from existing ltree path
-- Use ltree helpers: nlevel() and subpath()
UPDATE departments d1
SET parent_department_id = d2.id
    FROM departments d2
WHERE nlevel(d1.path) > 1
  AND d2.path = subpath(d1.path, 0, nlevel(d1.path) - 1);

-- 3) Guard against cycles/self-parent via trigger
CREATE OR REPLACE FUNCTION check_department_hierarchy()
RETURNS TRIGGER AS $$
DECLARE
current_id UUID;
    max_depth INT := 100;
    depth INT := 0;
BEGIN
    IF NEW.parent_department_id IS NULL THEN
        RETURN NEW;
END IF;

    -- self-reference
    IF NEW.parent_department_id = NEW.id THEN
        RAISE EXCEPTION 'Department cannot be its own parent';
END IF;

    -- walk up the tree
    current_id := NEW.parent_department_id;
    WHILE current_id IS NOT NULL AND depth < max_depth LOOP
        IF current_id = NEW.id THEN
            RAISE EXCEPTION 'Circular reference detected in department hierarchy';
END IF;

SELECT parent_department_id INTO current_id
FROM departments
WHERE id = current_id;

depth := depth + 1;
END LOOP;

    IF depth >= max_depth THEN
        RAISE EXCEPTION 'Department hierarchy too deep (max: %)', max_depth;
END IF;

RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS check_department_hierarchy_trigger ON departments;

CREATE TRIGGER check_department_hierarchy_trigger
    BEFORE INSERT OR UPDATE OF parent_department_id ON departments
    FOR EACH ROW
    EXECUTE FUNCTION check_department_hierarchy();

-- 4) Helper to rebuild dotted text path from codes (top.down.leaf)
CREATE OR REPLACE FUNCTION get_department_hierarchy_path(dept_id UUID)
RETURNS TEXT AS $$
DECLARE
path_text TEXT := '';
    current_dept RECORD;
    current_id UUID := dept_id;
BEGIN
    WHILE current_id IS NOT NULL LOOP
SELECT id, name, parent_department_id, code
INTO current_dept
FROM departments
WHERE id = current_id;

IF current_dept IS NULL THEN
            EXIT;
END IF;

        IF path_text = '' THEN
            path_text := current_dept.code;
ELSE
            path_text := current_dept.code || '.' || path_text;
END IF;

        current_id := current_dept.parent_department_id;
END LOOP;

RETURN path_text;
END;
$$ LANGUAGE plpgsql;

-- 5) View for easy hierarchy queries
CREATE OR REPLACE VIEW department_hierarchy AS
WITH RECURSIVE dept_tree AS (
    -- roots
    SELECT 
        id,
        name,
        code,
        parent_department_id,
        path,
        0  AS level,
        ARRAY[id]   AS hierarchy_ids,
        ARRAY[name] AS hierarchy_names
    FROM departments
    WHERE parent_department_id IS NULL

    UNION ALL

    -- children
    SELECT 
        d.id,
        d.name,
        d.code,
        d.parent_department_id,
        d.path,
        dt.level + 1,
        dt.hierarchy_ids   || d.id,
        dt.hierarchy_names || d.name
    FROM departments d
    JOIN dept_tree dt ON d.parent_department_id = dt.id
)
SELECT * FROM dept_tree;
