-- 권한 시스템 개선 마이그레이션
-- 새로운 사용자 역할 추가 및 개별 권한 테이블 생성

-- 1. 새로운 사용자 역할 추가
ALTER TYPE userrole ADD VALUE 'super_admin';
ALTER TYPE userrole ADD VALUE 'manager';

-- 2. 사용자별 개별 권한 테이블 생성
CREATE TABLE IF NOT EXISTS user_permissions (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    permission VARCHAR(50) NOT NULL,
    granted BOOLEAN DEFAULT TRUE,
    granted_by_id INTEGER REFERENCES users(id),
    granted_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    revoked_at TIMESTAMP WITH TIME ZONE,
    notes TEXT,
    UNIQUE(user_id, permission)
);

-- 3. 인덱스 생성
CREATE INDEX IF NOT EXISTS idx_user_permissions_user_id ON user_permissions(user_id);
CREATE INDEX IF NOT EXISTS idx_user_permissions_permission ON user_permissions(permission);
CREATE INDEX IF NOT EXISTS idx_user_permissions_granted ON user_permissions(granted);

-- 4. 기본 권한 설정 (기존 관리자에게 super_admin 권한 부여)
UPDATE users SET role = 'super_admin' WHERE username = 'hyungi';

-- 5. 권한 확인 함수 생성
CREATE OR REPLACE FUNCTION check_user_permission(p_user_id INTEGER, p_permission VARCHAR)
RETURNS BOOLEAN AS $$
DECLARE
    user_role userrole;
    has_permission BOOLEAN := FALSE;
BEGIN
    -- 사용자 역할 가져오기
    SELECT role INTO user_role FROM users WHERE id = p_user_id AND is_active = TRUE;
    
    IF user_role IS NULL THEN
        RETURN FALSE;
    END IF;
    
    -- super_admin은 모든 권한 보유
    IF user_role = 'super_admin' THEN
        RETURN TRUE;
    END IF;
    
    -- 개별 권한 확인
    SELECT granted INTO has_permission 
    FROM user_permissions 
    WHERE user_id = p_user_id 
      AND permission = p_permission 
      AND granted = TRUE 
      AND revoked_at IS NULL;
    
    -- 개별 권한이 없으면 역할 기반 기본 권한 확인
    IF has_permission IS NULL THEN
        -- 기본 권한 매트릭스
        CASE 
            WHEN p_permission IN ('issues.create', 'issues.view') THEN
                has_permission := TRUE; -- 모든 사용자
            WHEN p_permission IN ('issues.edit', 'issues.review', 'daily_work.create', 'daily_work.view', 'daily_work.edit') THEN
                has_permission := user_role IN ('admin', 'manager'); -- 관리자, 매니저
            WHEN p_permission IN ('projects.create', 'projects.edit', 'issues.delete', 'daily_work.delete') THEN
                has_permission := user_role = 'admin'; -- 관리자만
            WHEN p_permission IN ('projects.delete', 'users.create', 'users.edit', 'users.delete', 'users.change_role') THEN
                has_permission := user_role = 'super_admin'; -- 최고 관리자만
            ELSE
                has_permission := FALSE;
        END CASE;
    END IF;
    
    RETURN COALESCE(has_permission, FALSE);
END;
$$ LANGUAGE plpgsql;

-- 6. 권한 부여 함수 생성
CREATE OR REPLACE FUNCTION grant_user_permission(
    p_user_id INTEGER, 
    p_permission VARCHAR, 
    p_granted_by_id INTEGER,
    p_notes TEXT DEFAULT NULL
)
RETURNS BOOLEAN AS $$
BEGIN
    INSERT INTO user_permissions (user_id, permission, granted, granted_by_id, notes)
    VALUES (p_user_id, p_permission, TRUE, p_granted_by_id, p_notes)
    ON CONFLICT (user_id, permission) 
    DO UPDATE SET 
        granted = TRUE,
        granted_by_id = p_granted_by_id,
        granted_at = NOW(),
        revoked_at = NULL,
        notes = p_notes;
    
    RETURN TRUE;
END;
$$ LANGUAGE plpgsql;

-- 7. 권한 취소 함수 생성
CREATE OR REPLACE FUNCTION revoke_user_permission(
    p_user_id INTEGER, 
    p_permission VARCHAR, 
    p_revoked_by_id INTEGER,
    p_notes TEXT DEFAULT NULL
)
RETURNS BOOLEAN AS $$
BEGIN
    UPDATE user_permissions 
    SET granted = FALSE,
        revoked_at = NOW(),
        notes = p_notes
    WHERE user_id = p_user_id 
      AND permission = p_permission;
    
    RETURN TRUE;
END;
$$ LANGUAGE plpgsql;

-- 8. 사용자 권한 목록 조회 뷰 생성
CREATE OR REPLACE VIEW user_permissions_view AS
SELECT 
    u.id as user_id,
    u.username,
    u.full_name,
    u.role,
    up.permission,
    up.granted,
    up.granted_at,
    up.revoked_at,
    granted_by.username as granted_by_username,
    up.notes
FROM users u
LEFT JOIN user_permissions up ON u.id = up.user_id
LEFT JOIN users granted_by ON up.granted_by_id = granted_by.id
WHERE u.is_active = TRUE
ORDER BY u.username, up.permission;
