USE [2025_5bhitn_konstantin_hintermayer_smarter_rentDB];
GO


-- ####################################################
-- # STORED PROCEDURES                                #
-- ####################################################

-- Stored Procedure: sp_MieteFahrzeug
CREATE OR ALTER PROCEDURE sp_MieteFahrzeug
    @KundeID BIGINT,
    @FahrzeugID BIGINT,
    @Start DATE,
    @Ende DATE
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;
    
    DECLARE @VerfuegbareFahrzeuge INT;
    
    BEGIN TRY
        BEGIN TRANSACTION;
        
        -- Prüfe, ob Kunde existiert
        IF NOT EXISTS (SELECT 1 FROM Customer WHERE id = @KundeID)
        BEGIN
            RAISERROR('Kunde mit der angegebenen ID existiert nicht.', 16, 1);
        END;
        
        -- Prüfe, ob Fahrzeug existiert
        IF NOT EXISTS (SELECT 1 FROM Vehicle WHERE id = @FahrzeugID)
        BEGIN
            RAISERROR('Fahrzeug mit der angegebenen ID existiert nicht.', 16, 1);
        END;
        
        -- Prüfe, ob Enddatum nach Startdatum liegt
        IF @Ende <= @Start
        BEGIN
            RAISERROR('Das Enddatum muss nach dem Startdatum liegen.', 16, 1);
        END;
        
        -- Prüfe Verfügbarkeit des Fahrzeugs
        SELECT @VerfuegbareFahrzeuge = COUNT(*)
        FROM Rental
        WHERE vehicleID = @FahrzeugID
        -- Ein Fahrzeug ist besetzt, wenn der neue Zeitraum sich mit einem bestehenden überschneidet
        -- und noch nicht zurückgegeben wurde (actualEnd IS NULL)
        AND actualEnd IS NULL
        AND (
            (@Start < rentalEnd)
            AND (@Ende > rentalStart)
        );
        
        IF @VerfuegbareFahrzeuge > 0
        BEGIN
            RAISERROR('Das Fahrzeug ist im angegebenen Zeitraum nicht verfügbar.', 16, 1);
        END;
        
        -- Erstelle den Mietdatensatz
        -- Hinweis: actualEnd ist initial NULL
        INSERT INTO Rental (customerID, vehicleID, rentalStart, rentalEnd, actualEnd)
        VALUES (@KundeID, @FahrzeugID, @Start, @Ende, NULL);
        
        DECLARE @MietID BIGINT = SCOPE_IDENTITY();
        
        COMMIT TRANSACTION;
        
        -- Rückgabewert
        SELECT 
            @MietID AS id,
            'Mietvertrag erfolgreich erstellt.' AS message,
            @Start AS rentalStart,
            @Ende AS rentalEnd;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
        DECLARE @ErrMssp_MieteFahrzeug NVARCHAR(4000) = ERROR_MESSAGE();
        RAISERROR(@ErrMssp_MieteFahrzeug, 16, 1);
    END CATCH;
END;
GO

-- Stored Procedure: sp_RueckgabeFahrzeug
-- Aktualisiert actualEnd und berechnet Endpreis via UDF
-- Stored Procedure: sp_RueckgabeFahrzeug
-- Aktualisiert actualEnd und berechnet Endpreis via UDF
CREATE OR ALTER PROCEDURE sp_RueckgabeFahrzeug
    @MietID BIGINT,
    @RueckgabeDatum DATETIME
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;
    
    DECLARE @Tagespreis DECIMAL(10, 2);
    DECLARE @StartDatum DATE;
    DECLARE @Endpreis DECIMAL(10, 2);
    
    BEGIN TRY
        BEGIN TRANSACTION;
        
        -- Prüfe, ob Miet-ID existiert
        IF NOT EXISTS (SELECT 1 FROM Rental WHERE id = @MietID)
        BEGIN
            RAISERROR('Mietvertrag mit der angegebenen ID existiert nicht.', 16, 1);
        END;
        
        -- Hole Start-Datum und Tagespreis (aus VehicleCategory via Vehicle)
        SELECT 
            @StartDatum = r.rentalStart,
            @Tagespreis = vc.pricePerDay
        FROM Rental r
        JOIN Vehicle v ON r.vehicleID = v.id
        JOIN VehicleCategory vc ON v.vehicleCategoryID = vc.id
        WHERE r.id = @MietID;
        
        -- Berechne den Endpreis mit Hilfe der UDF aus Einheit 2
        SET @Endpreis = dbo.fn_BerechneMietkosten(@StartDatum, @RueckgabeDatum, @Tagespreis);
        
        -- Prüfe, ob Rückgabedatum nach Startdatum liegt
        IF @RueckgabeDatum < @StartDatum
        BEGIN
            RAISERROR('Das Rückgabedatum kann nicht vor dem Mietstart liegen.', 16, 1);
        END;
        
        -- Aktualisiere den Rental-Datensatz (actualEnd)
        UPDATE Rental
        SET 
            actualEnd = @RueckgabeDatum
        WHERE id = @MietID;
        
        COMMIT TRANSACTION;
        
        -- Rückgabewert
        SELECT 
            @MietID AS id,
            'Fahrzeug erfolgreich zurückgegeben.' AS message,
            @RueckgabeDatum AS actualEnd,
            @Endpreis AS calculatedTotalPrice;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
        DECLARE @ErrMssp_RueckgabeFahrzeug NVARCHAR(4000) = ERROR_MESSAGE();
        RAISERROR(@ErrMssp_RueckgabeFahrzeug, 16, 1);
    END CATCH;
END;
GO

-- =====================================================
-- TRIGGER
-- =====================================================

-- Hinweis: Die Status-Update Trigger wurden entfernt, da die Tabelle 'Vehicle'
-- laut Schema keine 'status' Spalte besitzt. Die Verfügbarkeit wird
-- dynamisch über Views (v_VerfuegbareFahrzeuge) ermittelt.

-- Archive table for Customer (if not exists)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='CustomerArchiv' AND xtype='U')
BEGIN
    CREATE TABLE CustomerArchiv (
        id BIGINT NOT NULL,
        name VARCHAR(50) NOT NULL,
        Adress VARCHAR(100) NOT NULL,
        driverlicenseid VARCHAR(100) NOT NULL,
        deletedDate DATETIME NOT NULL,
        PRIMARY KEY (id, deletedDate)
    );
END;
GO

-- Trigger: trg_Archivierung
-- Kopiert gelöschte Kunden in KundenArchiv-Tabelle statt physisch zu löschen
CREATE OR ALTER TRIGGER trg_Archivierung
ON Customer
INSTEAD OF DELETE
AS
BEGIN
    SET NOCOUNT ON;
    
    BEGIN TRY
        BEGIN TRANSACTION;
        
        -- Kopiere gelöschte Kunden in die Archiv-Tabelle
        INSERT INTO CustomerArchiv (id, name, Adress, driverlicenseid, deletedDate)
        SELECT 
            id,
            name,
            Adress,
            driverlicenseid,
            GETDATE()
        FROM deleted;
        
        -- Lösche den Datensatz nur, wenn die Archivierung erfolgreich war
        DELETE FROM Customer
        WHERE id IN (SELECT id FROM deleted);
        
        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;
        DECLARE @ErrMsstrg_Archivierung NVARCHAR(4000) = ERROR_MESSAGE();
        RAISERROR(@ErrMsstrg_Archivierung, 16, 1);
    END CATCH;
END;
GO