-- V014__create_tablas_fiscales.sql
-- ADM-009 Tablas Fiscales: DDL para dbo.TipoDeIva + dbo.IngresosBrutos + permisos.
--
-- Patron: append-only versioned ref data.
-- Porcentaje/Alicuota son INMUTABLES post-creacion; cambiar el valor = nueva fila + cierre de predecesora.
-- PredecesorId (FK self) establece la cadena de versiones (historial de negocio).
-- SYSTEM_VERSIONING ON para historial tecnico (auditoria temporal de SQL Server).
--
-- Idempotente: seguro para re-ejecutar.
-- Reversa: V014_ROLLBACK.sql.
-- Run on: SIGCM2 (dev) y SIGCM2_Test (integration tests).
--
-- Covers: REQ-SEED-001, REQ-SEED-002, REQ-SEED-003, REQ-TEMPORAL-001, REQ-FISCAL-AUTH-002

SET QUOTED_IDENTIFIER ON;
SET ANSI_NULLS ON;
SET NOCOUNT ON;
GO

-- ═══════════════════════════════════════════════════════════════════════
-- 1. dbo.TipoDeIva
-- ═══════════════════════════════════════════════════════════════════════

IF OBJECT_ID(N'dbo.TipoDeIva', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.TipoDeIva (
        Id                INT IDENTITY(1,1)  NOT NULL CONSTRAINT PK_TipoDeIva PRIMARY KEY,
        Codigo            VARCHAR(32)        NOT NULL,
        Descripcion       NVARCHAR(100)      NOT NULL,
        Porcentaje        DECIMAL(5,2)       NOT NULL,
        AplicaIVA         BIT                NOT NULL,
        Activo            BIT                NOT NULL CONSTRAINT DF_TipoDeIva_Activo            DEFAULT(1),
        VigenciaDesde     DATE               NOT NULL,
        VigenciaHasta     DATE               NULL,
        PredecesorId      INT                NULL,
        FechaCreacion     DATETIME2(3)       NOT NULL CONSTRAINT DF_TipoDeIva_FechaCreacion     DEFAULT(SYSUTCDATETIME()),
        FechaModificacion DATETIME2(3)       NULL,
        CONSTRAINT CK_TipoDeIva_Porcentaje  CHECK (Porcentaje >= 0 AND Porcentaje <= 100),
        CONSTRAINT CK_TipoDeIva_Vigencia    CHECK (VigenciaHasta IS NULL OR VigenciaHasta >= VigenciaDesde),
        CONSTRAINT UQ_TipoDeIva_Codigo_Vigencia UNIQUE (Codigo, VigenciaDesde),
        CONSTRAINT FK_TipoDeIva_Predecesor  FOREIGN KEY (PredecesorId) REFERENCES dbo.TipoDeIva(Id)
    );
    PRINT 'Table dbo.TipoDeIva created.';
END
ELSE
    PRINT 'Table dbo.TipoDeIva already exists — skip.';
GO

-- Indices TipoDeIva
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_TipoDeIva_Codigo_VigenciaDesde' AND object_id = OBJECT_ID('dbo.TipoDeIva'))
BEGIN
    CREATE INDEX IX_TipoDeIva_Codigo_VigenciaDesde
        ON dbo.TipoDeIva(Codigo, VigenciaDesde DESC);
    PRINT 'Index IX_TipoDeIva_Codigo_VigenciaDesde created.';
END
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_TipoDeIva_PredecesorId' AND object_id = OBJECT_ID('dbo.TipoDeIva'))
BEGIN
    CREATE INDEX IX_TipoDeIva_PredecesorId
        ON dbo.TipoDeIva(PredecesorId)
        WHERE PredecesorId IS NOT NULL;
    PRINT 'Index IX_TipoDeIva_PredecesorId created.';
END
GO

-- SYSTEM_VERSIONING — TipoDeIva
IF COL_LENGTH('dbo.TipoDeIva', 'ValidFrom') IS NULL
BEGIN
    ALTER TABLE dbo.TipoDeIva
    ADD
        ValidFrom DATETIME2(3) GENERATED ALWAYS AS ROW START HIDDEN NOT NULL
            CONSTRAINT DF_TipoDeIva_ValidFrom DEFAULT(SYSUTCDATETIME()),
        ValidTo   DATETIME2(3) GENERATED ALWAYS AS ROW END   HIDDEN NOT NULL
            CONSTRAINT DF_TipoDeIva_ValidTo   DEFAULT(CONVERT(DATETIME2(3), '9999-12-31 23:59:59.999')),
        PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);
    PRINT 'TipoDeIva: PERIOD FOR SYSTEM_TIME added.';
END
GO

IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('dbo.TipoDeIva') AND temporal_type = 2)
BEGIN
    ALTER TABLE dbo.TipoDeIva
    SET (SYSTEM_VERSIONING = ON (
        HISTORY_TABLE = dbo.TipoDeIva_History,
        HISTORY_RETENTION_PERIOD = 10 YEARS
    ));
    PRINT 'TipoDeIva: SYSTEM_VERSIONING = ON (history: dbo.TipoDeIva_History, retention: 10 years).';
END
ELSE
    PRINT 'TipoDeIva: SYSTEM_VERSIONING already ON — skip.';
GO

IF EXISTS (SELECT 1 FROM sys.tables WHERE name = 'TipoDeIva_History' AND schema_id = SCHEMA_ID('dbo'))
   AND NOT EXISTS (
       SELECT 1 FROM sys.partitions p
       JOIN sys.tables t ON t.object_id = p.object_id
       WHERE t.name = 'TipoDeIva_History' AND p.data_compression = 2
   )
BEGIN
    ALTER TABLE dbo.TipoDeIva_History REBUILD WITH (DATA_COMPRESSION = PAGE);
    PRINT 'TipoDeIva_History: rebuilt with PAGE compression.';
END
GO

-- ═══════════════════════════════════════════════════════════════════════
-- 2. dbo.IngresosBrutos
-- ═══════════════════════════════════════════════════════════════════════

IF OBJECT_ID(N'dbo.IngresosBrutos', N'U') IS NULL
BEGIN
    CREATE TABLE dbo.IngresosBrutos (
        Id                INT IDENTITY(1,1)  NOT NULL CONSTRAINT PK_IngresosBrutos PRIMARY KEY,
        Provincia         VARCHAR(50)        NOT NULL,
        Descripcion       NVARCHAR(100)      NOT NULL,
        Alicuota          DECIMAL(5,2)       NOT NULL,
        Activo            BIT                NOT NULL CONSTRAINT DF_IIBB_Activo            DEFAULT(1),
        VigenciaDesde     DATE               NOT NULL,
        VigenciaHasta     DATE               NULL,
        PredecesorId      INT                NULL,
        FechaCreacion     DATETIME2(3)       NOT NULL CONSTRAINT DF_IIBB_FechaCreacion     DEFAULT(SYSUTCDATETIME()),
        FechaModificacion DATETIME2(3)       NULL,
        CONSTRAINT CK_IIBB_Alicuota         CHECK (Alicuota >= 0 AND Alicuota <= 100),
        CONSTRAINT CK_IIBB_Vigencia         CHECK (VigenciaHasta IS NULL OR VigenciaHasta >= VigenciaDesde),
        CONSTRAINT UQ_IIBB_Provincia_Vigencia UNIQUE (Provincia, VigenciaDesde),
        CONSTRAINT FK_IIBB_Predecesor       FOREIGN KEY (PredecesorId) REFERENCES dbo.IngresosBrutos(Id)
    );
    PRINT 'Table dbo.IngresosBrutos created.';
END
ELSE
    PRINT 'Table dbo.IngresosBrutos already exists — skip.';
GO

-- Indices IngresosBrutos
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_IIBB_Provincia_VigenciaDesde' AND object_id = OBJECT_ID('dbo.IngresosBrutos'))
BEGIN
    CREATE INDEX IX_IIBB_Provincia_VigenciaDesde
        ON dbo.IngresosBrutos(Provincia, VigenciaDesde DESC);
    PRINT 'Index IX_IIBB_Provincia_VigenciaDesde created.';
END
GO

IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_IIBB_PredecesorId' AND object_id = OBJECT_ID('dbo.IngresosBrutos'))
BEGIN
    CREATE INDEX IX_IIBB_PredecesorId
        ON dbo.IngresosBrutos(PredecesorId)
        WHERE PredecesorId IS NOT NULL;
    PRINT 'Index IX_IIBB_PredecesorId created.';
END
GO

-- SYSTEM_VERSIONING — IngresosBrutos
IF COL_LENGTH('dbo.IngresosBrutos', 'ValidFrom') IS NULL
BEGIN
    ALTER TABLE dbo.IngresosBrutos
    ADD
        ValidFrom DATETIME2(3) GENERATED ALWAYS AS ROW START HIDDEN NOT NULL
            CONSTRAINT DF_IIBB_ValidFrom DEFAULT(SYSUTCDATETIME()),
        ValidTo   DATETIME2(3) GENERATED ALWAYS AS ROW END   HIDDEN NOT NULL
            CONSTRAINT DF_IIBB_ValidTo   DEFAULT(CONVERT(DATETIME2(3), '9999-12-31 23:59:59.999')),
        PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo);
    PRINT 'IngresosBrutos: PERIOD FOR SYSTEM_TIME added.';
END
GO

IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('dbo.IngresosBrutos') AND temporal_type = 2)
BEGIN
    ALTER TABLE dbo.IngresosBrutos
    SET (SYSTEM_VERSIONING = ON (
        HISTORY_TABLE = dbo.IngresosBrutos_History,
        HISTORY_RETENTION_PERIOD = 10 YEARS
    ));
    PRINT 'IngresosBrutos: SYSTEM_VERSIONING = ON (history: dbo.IngresosBrutos_History, retention: 10 years).';
END
ELSE
    PRINT 'IngresosBrutos: SYSTEM_VERSIONING already ON — skip.';
GO

IF EXISTS (SELECT 1 FROM sys.tables WHERE name = 'IngresosBrutos_History' AND schema_id = SCHEMA_ID('dbo'))
   AND NOT EXISTS (
       SELECT 1 FROM sys.partitions p
       JOIN sys.tables t ON t.object_id = p.object_id
       WHERE t.name = 'IngresosBrutos_History' AND p.data_compression = 2
   )
BEGIN
    ALTER TABLE dbo.IngresosBrutos_History REBUILD WITH (DATA_COMPRESSION = PAGE);
    PRINT 'IngresosBrutos_History: rebuilt with PAGE compression.';
END
GO

-- ═══════════════════════════════════════════════════════════════════════
-- 3. Seed TipoDeIva — 4 filas canonicas (REQ-SEED-001)
--    MERGE garantiza idempotencia (REQ-SEED-003)
--    EXENTO y NO_GRAVADO no aplican IVA; IVA_105 e IVA_21 si aplican.
-- ═══════════════════════════════════════════════════════════════════════

MERGE dbo.TipoDeIva AS t
USING (VALUES
    ('EXENTO',     N'Exento de IVA',               CAST(0    AS DECIMAL(5,2)), CAST(0 AS BIT), CAST('2020-01-01' AS DATE)),
    ('NO_GRAVADO', N'No gravado',                   CAST(0    AS DECIMAL(5,2)), CAST(0 AS BIT), CAST('2020-01-01' AS DATE)),
    ('IVA_105',    N'IVA alicuota diferencial 10.5%', CAST(10.5 AS DECIMAL(5,2)), CAST(1 AS BIT), CAST('2020-01-01' AS DATE)),
    ('IVA_21',     N'IVA alicuota general 21%',    CAST(21   AS DECIMAL(5,2)), CAST(1 AS BIT), CAST('2020-01-01' AS DATE))
) AS s (Codigo, Descripcion, Porcentaje, AplicaIVA, VigenciaDesde)
ON t.Codigo = s.Codigo AND t.PredecesorId IS NULL
WHEN NOT MATCHED BY TARGET THEN
    INSERT (Codigo, Descripcion, Porcentaje, AplicaIVA, Activo, VigenciaDesde, VigenciaHasta, PredecesorId)
    VALUES (s.Codigo, s.Descripcion, s.Porcentaje, s.AplicaIVA, 1, s.VigenciaDesde, NULL, NULL);
GO

PRINT 'TipoDeIva: 4 canonical rows seeded (EXENTO, NO_GRAVADO, IVA_105, IVA_21).';
GO

-- ═══════════════════════════════════════════════════════════════════════
-- 4. Seed IngresosBrutos — 24 filas (23 provincias INDEC + CABA) (REQ-SEED-002)
--    Alicuota=0 placeholder — el operador cargara las alicuotas reales via UI.
--    MERGE garantiza idempotencia (REQ-SEED-003).
--    Provincias almacenadas como nombre de enum ProvinciaArgentina PascalCase (VARCHAR(50)).
--    DISCOVERY: spec dice 25 filas pero lista canonica del design tiene 24 entradas
--    (23 provincias INDEC + CABA). Implementado con 24. Ver apply-progress.
--    T700 cleanup: valores cambiados de UPPER_SNAKE_CASE a PascalCase (matching enum.ToString()).
-- ═══════════════════════════════════════════════════════════════════════

MERGE dbo.IngresosBrutos AS t
USING (VALUES
    ('BuenosAires',                  N'Ingresos Brutos - Buenos Aires'),
    ('CiudadAutonomaDeBuenosAires',  N'Ingresos Brutos - Ciudad Autonoma de Buenos Aires'),
    ('Catamarca',                    N'Ingresos Brutos - Catamarca'),
    ('Chaco',                        N'Ingresos Brutos - Chaco'),
    ('Chubut',                       N'Ingresos Brutos - Chubut'),
    ('Cordoba',                      N'Ingresos Brutos - Cordoba'),
    ('Corrientes',                   N'Ingresos Brutos - Corrientes'),
    ('EntreRios',                    N'Ingresos Brutos - Entre Rios'),
    ('Formosa',                      N'Ingresos Brutos - Formosa'),
    ('Jujuy',                        N'Ingresos Brutos - Jujuy'),
    ('LaPampa',                      N'Ingresos Brutos - La Pampa'),
    ('LaRioja',                      N'Ingresos Brutos - La Rioja'),
    ('Mendoza',                      N'Ingresos Brutos - Mendoza'),
    ('Misiones',                     N'Ingresos Brutos - Misiones'),
    ('Neuquen',                      N'Ingresos Brutos - Neuquen'),
    ('RioNegro',                     N'Ingresos Brutos - Rio Negro'),
    ('Salta',                        N'Ingresos Brutos - Salta'),
    ('SanJuan',                      N'Ingresos Brutos - San Juan'),
    ('SanLuis',                      N'Ingresos Brutos - San Luis'),
    ('SantaCruz',                    N'Ingresos Brutos - Santa Cruz'),
    ('SantaFe',                      N'Ingresos Brutos - Santa Fe'),
    ('SantiagoDelEstero',            N'Ingresos Brutos - Santiago del Estero'),
    ('TierraDelFuego',               N'Ingresos Brutos - Tierra del Fuego'),
    ('Tucuman',                      N'Ingresos Brutos - Tucuman')
) AS s (Provincia, Descripcion)
ON t.Provincia = s.Provincia AND t.PredecesorId IS NULL
WHEN NOT MATCHED BY TARGET THEN
    INSERT (Provincia, Descripcion, Alicuota, Activo, VigenciaDesde, VigenciaHasta, PredecesorId)
    VALUES (s.Provincia, s.Descripcion, CAST(0 AS DECIMAL(5,2)), 1, CAST('2020-01-01' AS DATE), NULL, NULL);
GO

PRINT 'IngresosBrutos: 24 canonical rows seeded (23 provincias INDEC + CABA, Alicuota=0 placeholder, PascalCase).';
GO

-- ═══════════════════════════════════════════════════════════════════════
-- 5. Permiso: administracion:fiscal:gestionar (REQ-FISCAL-AUTH-002)
-- ═══════════════════════════════════════════════════════════════════════

MERGE dbo.Permiso AS t
USING (VALUES
    ('administracion:fiscal:gestionar', N'Gestionar tablas fiscales', N'Gestionar tablas fiscales (IVA, IIBB)', 'administracion')
) AS s (Codigo, Nombre, Descripcion, Modulo)
ON t.Codigo = s.Codigo
WHEN NOT MATCHED BY TARGET THEN
    INSERT (Codigo, Nombre, Descripcion, Modulo)
    VALUES (s.Codigo, s.Nombre, s.Descripcion, s.Modulo);
GO

MERGE dbo.RolPermiso AS t
USING (
    SELECT r.Id AS RolId, p.Id AS PermisoId
    FROM (VALUES
        ('admin', 'administracion:fiscal:gestionar')
    ) AS x (RolCodigo, PermisoCodigo)
    JOIN dbo.Rol     r ON r.Codigo = x.RolCodigo
    JOIN dbo.Permiso p ON p.Codigo = x.PermisoCodigo
) AS s ON t.RolId = s.RolId AND t.PermisoId = s.PermisoId
WHEN NOT MATCHED BY TARGET THEN
    INSERT (RolId, PermisoId) VALUES (s.RolId, s.PermisoId);
GO

PRINT '';
PRINT 'V014 applied successfully.';
PRINT '  - dbo.TipoDeIva (temporal, retention 10y, PAGE compression)';
PRINT '  - dbo.IngresosBrutos (temporal, retention 10y, PAGE compression)';
PRINT '  - TipoDeIva: 4 canonical rows (EXENTO, NO_GRAVADO, IVA_105, IVA_21)';
PRINT '  - IngresosBrutos: 24 rows (23 provincias INDEC + CABA, Alicuota=0 placeholder)';
PRINT '  - Permiso administracion:fiscal:gestionar (asignado a admin)';
GO
