-- 1. Create Public Holidays Table
CREATE TABLE IF NOT EXISTS public.public_holidays (
    id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
    date DATE NOT NULL UNIQUE,
    name TEXT NOT NULL,
    is_recurring BOOLEAN DEFAULT false, -- If true, year is ignored (e.g., Oct 29)
    created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);

-- Seed some recurring Turkish public holidays
INSERT INTO public.public_holidays (date, name, is_recurring) VALUES
('2024-01-01', 'Yılbaşı', true),
('2024-04-23', 'Ulusal Egemenlik ve Çocuk Bayramı', true),
('2024-05-01', 'Emek ve Dayanışma Günü', true),
('2024-05-19', 'Atatürk''ü Anma, Gençlik ve Spor Bayramı', true),
('2024-07-15', 'Demokrasi ve Milli Birlik Günü', true),
('2024-08-30', 'Zafer Bayramı', true),
('2024-10-29', 'Cumhuriyet Bayramı', true)
ON CONFLICT (date) DO NOTHING;

-- 2. Create Leave Types Table
CREATE TABLE IF NOT EXISTS public.leave_types (
    id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
    name TEXT NOT NULL UNIQUE,
    description TEXT,
    is_paid BOOLEAN DEFAULT true,
    requires_approval BOOLEAN DEFAULT true,
    is_deductible BOOLEAN DEFAULT true, -- If true, reduces standard balance
    only_admin_can_create BOOLEAN DEFAULT false, -- If true, only managers/admins can initiate
    color_code TEXT,
    display_order INTEGER DEFAULT 99, -- Sort order for UI
    created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
);

-- Add column if it doesn't exist (for cases where table already existed)
DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_types' AND column_name='display_order') THEN
        ALTER TABLE public.leave_types ADD COLUMN display_order INTEGER DEFAULT 99;
    END IF;
END $$;

-- Seed Leave Types with display_order
INSERT INTO public.leave_types (name, description, is_paid, requires_approval, is_deductible, only_admin_can_create, color_code, display_order) VALUES
('Yıllık İzin', 'Kıdeme bağlı hakedilen ücretli izin', true, true, true, false, '#4CAF50', 1),
('Mazeret İzni', 'Özel durumlar için kısa süreli izinler', true, true, true, false, '#FF9800', 2),
('Hastalık İzni', 'Raporlu olunan günler', true, true, false, false, '#F44336', 3),
('Evlilik İzni', 'Evlilik durumunda verilen 3 günlük yasal izin', true, true, false, false, '#E91E63', 4),
('Vefat İzni', 'Birinci derece yakın vefatı durumunda verilen 3 günlük yasal izin', true, true, false, false, '#607D8B', 5),
('İdari İzin', 'Yönetim tarafından verilen idari izin', true, true, false, true, '#2196F3', 6),
('İcap', 'Nöbet/İcap görevleri için verilen izin', true, true, false, true, '#9C27B0', 7)
ON CONFLICT (name) DO UPDATE SET display_order = EXCLUDED.display_order;

-- 3. Modify Leave Requests Table
-- First, add columns (handle case where they might already exist if re-run)
DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_requests' AND column_name='leave_type_id') THEN
        ALTER TABLE public.leave_requests ADD COLUMN leave_type_id UUID REFERENCES public.leave_types(id);
    END IF;
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_requests' AND column_name='total_days') THEN
        ALTER TABLE public.leave_requests ADD COLUMN total_days DECIMAL(5,2);
    END IF;
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_requests' AND column_name='approved_by') THEN
        ALTER TABLE public.leave_requests ADD COLUMN approved_by UUID REFERENCES auth.users(id);
    END IF;
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_requests' AND column_name='approval_date') THEN
        ALTER TABLE public.leave_requests ADD COLUMN approval_date TIMESTAMP WITH TIME ZONE;
    END IF;
END $$;

-- 4. Update Leave Balances Table
-- We need to drop the unique constraint on employee_id because now it's employee_id + leave_type_id + year
ALTER TABLE public.leave_balances DROP CONSTRAINT IF EXISTS leave_balances_employee_id_key;

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_balances' AND column_name='leave_type_id') THEN
        ALTER TABLE public.leave_balances ADD COLUMN leave_type_id UUID REFERENCES public.leave_types(id);
    END IF;
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_balances' AND column_name='year') THEN
        ALTER TABLE public.leave_balances ADD COLUMN year INTEGER DEFAULT EXTRACT(YEAR FROM CURRENT_DATE);
    END IF;
    IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='leave_balances' AND column_name='accrued_days') THEN
        ALTER TABLE public.leave_balances ADD COLUMN accrued_days DECIMAL(5,2) DEFAULT 0;
    END IF;
END $$;

-- Update existing data: map annual leave type to existing balances
DO $$
DECLARE
    annual_leave_id UUID;
BEGIN
    SELECT id INTO annual_leave_id FROM public.leave_types WHERE name = 'Yıllık İzin' LIMIT 1;
    
    UPDATE public.leave_balances SET leave_type_id = annual_leave_id WHERE leave_type_id IS NULL;
    UPDATE public.leave_requests SET leave_type_id = annual_leave_id WHERE leave_type_id IS NULL;
END $$;

-- Now add NOT NULL and UNIQUE constraint
ALTER TABLE public.leave_balances ALTER COLUMN leave_type_id SET NOT NULL;

DO $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'leave_balances_employee_type_year_unique') THEN
        ALTER TABLE public.leave_balances ADD CONSTRAINT leave_balances_employee_type_year_unique UNIQUE(employee_id, leave_type_id, year);
    END IF;
END $$;

-- 5. Helper Function: Calculate Leave Days
CREATE OR REPLACE FUNCTION public.calculate_leave_days(p_start_date DATE, p_end_date DATE)
RETURNS DECIMAL AS $$
DECLARE
    curr_date DATE;
    total_days DECIMAL := 0;
    is_holiday BOOLEAN;
BEGIN
    curr_date := p_start_date;
    WHILE curr_date <= p_end_date LOOP
        -- Sunday (0) is never counts. 
        -- Saturday logic: Depends on company, but generally counts in law. 
        -- We'll exclude Sundays and Public Holidays.
        IF EXTRACT(DOW FROM curr_date) != 0 THEN
            SELECT EXISTS(
                SELECT 1 FROM public.public_holidays 
                WHERE (is_recurring AND EXTRACT(MONTH FROM date) = EXTRACT(MONTH FROM curr_date) AND EXTRACT(DAY FROM date) = EXTRACT(DAY FROM curr_date))
                OR (NOT is_recurring AND date = curr_date)
            ) INTO is_holiday;
            
            IF NOT is_holiday THEN
                total_days := total_days + 1;
            END IF;
        END IF;
        curr_date := curr_date + 1;
    END LOOP;
    RETURN total_days;
END;
$$ LANGUAGE plpgsql;

-- 6. Trigger to auto-calculate total_days on leave_requests
CREATE OR REPLACE FUNCTION public.handle_leave_request_days()
RETURNS TRIGGER AS $$
BEGIN
    NEW.total_days := public.calculate_leave_days(NEW.start_date, NEW.end_date);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS tr_calculate_leave_days ON public.leave_requests;
CREATE TRIGGER tr_calculate_leave_days
BEFORE INSERT OR UPDATE OF start_date, end_date ON public.leave_requests
FOR EACH ROW EXECUTE PROCEDURE public.handle_leave_request_days();

-- 7. Seniority based Accrual Function
CREATE OR REPLACE FUNCTION public.calculate_annual_leave_entitlement(p_employee_id UUID)
RETURNS INTEGER AS $$
DECLARE
    v_hire_date DATE;
    v_years_service INTEGER;
BEGIN
    SELECT COALESCE(start_date, hire_date, created_at::date) INTO v_hire_date 
    FROM public.employees WHERE id = p_employee_id;
    
    v_years_service := EXTRACT(YEAR FROM age(CURRENT_DATE, v_hire_date));
    
    IF v_years_service < 1 THEN RETURN 0; -- No leave in first year
    ELSIF v_years_service < 5 THEN RETURN 14;
    ELSIF v_years_service < 15 THEN RETURN 20;
    ELSE RETURN 26;
    END IF;
END;
$$ LANGUAGE plpgsql;

-- 8. Updated Balance Trigger
-- We need to replace handle_new_employee_balance to handle new logic
CREATE OR REPLACE FUNCTION public.handle_new_employee_balance()
RETURNS TRIGGER AS $$
DECLARE
    annual_leave_id UUID;
BEGIN
    SELECT id INTO annual_leave_id FROM public.leave_types WHERE name = 'Yıllık İzin' LIMIT 1;
    
    INSERT INTO public.leave_balances (employee_id, leave_type_id, year, accrued_days, total_days)
    VALUES (NEW.id, annual_leave_id, EXTRACT(YEAR FROM CURRENT_DATE), 0, 0)
    ON CONFLICT DO NOTHING;
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- 9. Function to update balance based on leave request status
CREATE OR REPLACE FUNCTION public.update_leave_balance_on_status_change()
RETURNS TRIGGER AS $$
DECLARE
    v_is_deductible BOOLEAN;
    v_annual_leave_id UUID;
    v_year INTEGER;
BEGIN
    SELECT is_deductible INTO v_is_deductible FROM public.leave_types WHERE id = NEW.leave_type_id;
    
    IF v_is_deductible THEN
        v_year := EXTRACT(YEAR FROM NEW.start_date);
        
        -- Ensure balance record exists for this year/type
        INSERT INTO public.leave_balances (employee_id, leave_type_id, year)
        VALUES (NEW.employee_id, NEW.leave_type_id, v_year)
        ON CONFLICT (employee_id, leave_type_id, year) DO NOTHING;
        
        -- Update based on status
        IF NEW.status = 'approved' AND (OLD.status IS NULL OR OLD.status != 'approved') THEN
            UPDATE public.leave_balances 
            SET used_days = used_days + NEW.total_days,
                pending_days = CASE WHEN OLD.status = 'pending' THEN pending_days - NEW.total_days ELSE pending_days END
            WHERE employee_id = NEW.employee_id AND leave_type_id = NEW.leave_type_id AND year = v_year;
        ELSIF NEW.status = 'pending' AND (OLD.status IS NULL OR OLD.status != 'pending') THEN
            UPDATE public.leave_balances 
            SET pending_days = pending_days + NEW.total_days
            WHERE employee_id = NEW.employee_id AND leave_type_id = NEW.leave_type_id AND year = v_year;
        ELSIF (NEW.status = 'rejected' OR NEW.status = 'cancelled') AND OLD.status = 'pending' THEN
            UPDATE public.leave_balances 
            SET pending_days = pending_days - NEW.total_days
            WHERE employee_id = NEW.employee_id AND leave_type_id = NEW.leave_type_id AND year = v_year;
        ELSIF (NEW.status = 'cancelled') AND OLD.status = 'approved' THEN
            UPDATE public.leave_balances 
            SET used_days = used_days - NEW.total_days
            WHERE employee_id = NEW.employee_id AND leave_type_id = NEW.leave_type_id AND year = v_year;
        END IF;
    END IF;
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- 10. Update RLS for leave_balances (ensure proper access)
ALTER TABLE public.leave_balances ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS "Admins can do everything on leave_balances" ON public.leave_balances;
CREATE POLICY "Admins can do everything on leave_balances"
ON public.leave_balances
FOR ALL TO authenticated
USING (
    EXISTS (
        SELECT 1 FROM public.employees e
        JOIN public.roles r ON e.role_id = r.id
        WHERE e.user_id = auth.uid() AND r.name IN ('admin', 'manager')
    )
);

DROP POLICY IF EXISTS "Users can view their own leave balance" ON public.leave_balances;
CREATE POLICY "Users can view their own leave balance"
ON public.leave_balances
FOR SELECT TO authenticated
USING (
    employee_id IN (
        SELECT id FROM public.employees WHERE user_id = auth.uid()
    )
);

DROP TRIGGER IF EXISTS tr_update_leave_balance ON public.leave_requests;
CREATE TRIGGER tr_update_leave_balance
AFTER INSERT OR UPDATE OF status ON public.leave_requests
FOR EACH ROW EXECUTE PROCEDURE public.update_leave_balance_on_status_change();
