BEGIN;

CREATE TABLE IF NOT EXISTS fiscal_profiles (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  nif VARCHAR(32) NOT NULL,
  nin VARCHAR(32),
  article_imposition VARCHAR(64),
  forme_juridique VARCHAR(100),
  code_activite VARCHAR(4),
  activity_description TEXT,
  regime VARCHAR(20) NOT NULL DEFAULT 'IFU',
  statut_contribuable VARCHAR(30) NOT NULL DEFAULT 'normal',
  exoneration_type VARCHAR(30) NOT NULL DEFAULT 'none',
  exoneration_flags JSONB NOT NULL DEFAULT '[]'::jsonb,
  taux_ifu_marchandises NUMERIC(8, 2) NOT NULL DEFAULT 5,
  taux_ifu_services NUMERIC(8, 2) NOT NULL DEFAULT 12,
  taux_ifu_auto_entrepreneur NUMERIC(8, 2) NOT NULL DEFAULT 0.5,
  minimum_imposition_standard NUMERIC(18, 2) NOT NULL DEFAULT 30000,
  minimum_imposition_auto_entrepreneur NUMERIC(18, 2) NOT NULL DEFAULT 10000,
  option_regime_reel BOOLEAN NOT NULL DEFAULT FALSE,
  date_notification_regime_reel DATE,
  obligation_gn12_previsionnelle BOOLEAN NOT NULL DEFAULT TRUE,
  obligation_gn12_bis BOOLEAN NOT NULL DEFAULT TRUE,
  obligation_g50ter BOOLEAN NOT NULL DEFAULT FALSE,
  obligation_g50_tva BOOLEAN NOT NULL DEFAULT FALSE,
  obligation_g50_tls BOOLEAN NOT NULL DEFAULT FALSE,
  obligation_g50_ibs_icbs BOOLEAN NOT NULL DEFAULT FALSE,
  g50_periodicite VARCHAR(20) NOT NULL DEFAULT 'mensuel',
  is_assujetti_tva BOOLEAN NOT NULL DEFAULT FALSE,
  is_assujetti_tls BOOLEAN NOT NULL DEFAULT FALSE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT uq_fiscal_profiles_company UNIQUE (company_id),
  CONSTRAINT chk_fiscal_profiles_regime CHECK (regime IN ('IFU', 'reel', 'simplifie')),
  CONSTRAINT chk_fiscal_profiles_statut CHECK (
    statut_contribuable IN ('normal', 'auto_entrepreneur', 'nouveau')
  ),
  CONSTRAINT chk_fiscal_profiles_exoneration CHECK (
    exoneration_type IN ('none', 'ANADE', 'CNAC', 'ANGEM', 'artisanat', 'autre')
  ),
  CONSTRAINT chk_fiscal_profiles_code_activite CHECK (
    code_activite IS NULL OR code_activite ~ '^[0-9]{4}$'
  ),
  CONSTRAINT chk_fiscal_profiles_g50_periodicite CHECK (
    g50_periodicite IN ('mensuel', 'trimestriel')
  )
);

CREATE INDEX IF NOT EXISTS idx_fiscal_profiles_company_id ON fiscal_profiles (company_id);

ALTER TABLE fiscal_profiles
  ADD COLUMN IF NOT EXISTS activity_description TEXT,
  ADD COLUMN IF NOT EXISTS exoneration_flags JSONB NOT NULL DEFAULT '[]'::jsonb,
  ADD COLUMN IF NOT EXISTS minimum_imposition_standard NUMERIC(18, 2) NOT NULL DEFAULT 30000,
  ADD COLUMN IF NOT EXISTS minimum_imposition_auto_entrepreneur NUMERIC(18, 2) NOT NULL DEFAULT 10000,
  ADD COLUMN IF NOT EXISTS option_regime_reel BOOLEAN NOT NULL DEFAULT FALSE,
  ADD COLUMN IF NOT EXISTS date_notification_regime_reel DATE,
  ADD COLUMN IF NOT EXISTS obligation_gn12_previsionnelle BOOLEAN NOT NULL DEFAULT TRUE,
  ADD COLUMN IF NOT EXISTS obligation_gn12_bis BOOLEAN NOT NULL DEFAULT TRUE,
  ADD COLUMN IF NOT EXISTS obligation_g50ter BOOLEAN NOT NULL DEFAULT FALSE,
  ADD COLUMN IF NOT EXISTS obligation_g50_tva BOOLEAN NOT NULL DEFAULT FALSE,
  ADD COLUMN IF NOT EXISTS obligation_g50_tls BOOLEAN NOT NULL DEFAULT FALSE,
  ADD COLUMN IF NOT EXISTS obligation_g50_ibs_icbs BOOLEAN NOT NULL DEFAULT FALSE,
  ADD COLUMN IF NOT EXISTS g50_periodicite VARCHAR(20) NOT NULL DEFAULT 'mensuel';

DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conname = 'chk_fiscal_profiles_g50_periodicite'
  ) THEN
    ALTER TABLE fiscal_profiles
      ADD CONSTRAINT chk_fiscal_profiles_g50_periodicite CHECK (
        g50_periodicite IN ('mensuel', 'trimestriel')
      );
  END IF;
END $$;

CREATE TABLE IF NOT EXISTS ifu_declarations_previsionnelles (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  fiscal_year_id BIGINT NOT NULL REFERENCES fiscal_years (id) ON DELETE CASCADE,
  annee INTEGER NOT NULL,
  direction_wilaya VARCHAR(255),
  diw VARCHAR(100),
  recette VARCHAR(255),
  commune VARCHAR(150),
  nom_raison_sociale VARCHAR(255),
  activites_exercees TEXT,
  date_debut_activite DATE,
  adresse_lieu_exercice TEXT,
  adresse_domicile TEXT,
  exoneration_flags JSONB NOT NULL DEFAULT '[]'::jsonb,
  ca_marchandises_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_marchandises NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_services NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_auto_entrepreneur_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_auto_entrepreneur_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_auto_entrepreneur NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  marge_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_marge NUMERIC(18, 2) NOT NULL DEFAULT 0,
  is_marge_reglementee BOOLEAN NOT NULL DEFAULT FALSE,
  ifu_total_ca NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_total_marge NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_ifu_du NUMERIC(18, 2) NOT NULL DEFAULT 0,
  montant_effectif_a_payer NUMERIC(18, 2) NOT NULL DEFAULT 0,
  mode_paiement VARCHAR(20) NOT NULL DEFAULT 'integral',
  paiement_integral_montant NUMERIC(18, 2) NOT NULL DEFAULT 0,
  paiement_integral_quittance VARCHAR(100),
  paiement_integral_date DATE,
  tranche1_montant NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tranche1_date DATE,
  tranche1_quittance VARCHAR(100),
  tranche2_montant NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tranche2_date DATE,
  tranche2_quittance VARCHAR(100),
  tranche3_montant NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tranche3_date DATE,
  tranche3_quittance VARCHAR(100),
  minimum_imposition NUMERIC(18, 2) NOT NULL DEFAULT 0,
  lieu_declaration VARCHAR(255),
  date_signature DATE,
  statut VARCHAR(20) NOT NULL DEFAULT 'brouillon',
  date_depot DATE,
  submitted_at TIMESTAMPTZ,
  validated_at TIMESTAMPTZ,
  created_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  validated_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT uq_ifu_decl_prev_company_year UNIQUE (company_id, fiscal_year_id),
  CONSTRAINT chk_ifu_decl_prev_mode_paiement CHECK (
    mode_paiement IN ('integral', 'fractionne', 'minimum')
  ),
  CONSTRAINT chk_ifu_decl_prev_statut CHECK (
    statut IN ('brouillon', 'deposee', 'validee')
  )
);

CREATE INDEX IF NOT EXISTS idx_ifu_decl_prev_company_id
  ON ifu_declarations_previsionnelles (company_id);
CREATE INDEX IF NOT EXISTS idx_ifu_decl_prev_fiscal_year_id
  ON ifu_declarations_previsionnelles (fiscal_year_id);
CREATE INDEX IF NOT EXISTS idx_ifu_decl_prev_annee
  ON ifu_declarations_previsionnelles (annee);
CREATE INDEX IF NOT EXISTS idx_ifu_decl_prev_statut
  ON ifu_declarations_previsionnelles (statut);

ALTER TABLE ifu_declarations_previsionnelles
  ADD COLUMN IF NOT EXISTS direction_wilaya VARCHAR(255),
  ADD COLUMN IF NOT EXISTS diw VARCHAR(100),
  ADD COLUMN IF NOT EXISTS recette VARCHAR(255),
  ADD COLUMN IF NOT EXISTS commune VARCHAR(150),
  ADD COLUMN IF NOT EXISTS nom_raison_sociale VARCHAR(255),
  ADD COLUMN IF NOT EXISTS activites_exercees TEXT,
  ADD COLUMN IF NOT EXISTS date_debut_activite DATE,
  ADD COLUMN IF NOT EXISTS adresse_lieu_exercice TEXT,
  ADD COLUMN IF NOT EXISTS adresse_domicile TEXT,
  ADD COLUMN IF NOT EXISTS exoneration_flags JSONB NOT NULL DEFAULT '[]'::jsonb,
  ADD COLUMN IF NOT EXISTS is_marge_reglementee BOOLEAN NOT NULL DEFAULT FALSE,
  ADD COLUMN IF NOT EXISTS ifu_total_ca NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ifu_total_marge NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS montant_effectif_a_payer NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS paiement_integral_montant NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS paiement_integral_quittance VARCHAR(100),
  ADD COLUMN IF NOT EXISTS paiement_integral_date DATE,
  ADD COLUMN IF NOT EXISTS lieu_declaration VARCHAR(255),
  ADD COLUMN IF NOT EXISTS date_signature DATE,
  ADD COLUMN IF NOT EXISTS submitted_at TIMESTAMPTZ,
  ADD COLUMN IF NOT EXISTS validated_at TIMESTAMPTZ,
  ADD COLUMN IF NOT EXISTS validated_by BIGINT REFERENCES users (id) ON DELETE SET NULL;

CREATE TABLE IF NOT EXISTS ifu_declarations_definitives (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  fiscal_year_id BIGINT NOT NULL REFERENCES fiscal_years (id) ON DELETE CASCADE,
  annee INTEGER NOT NULL,
  direction_wilaya VARCHAR(255),
  diw VARCHAR(100),
  recette VARCHAR(255),
  commune VARCHAR(150),
  nom_raison_sociale VARCHAR(255),
  activites_exercees TEXT,
  periode_du DATE,
  periode_au DATE,
  date_debut_activite DATE,
  adresse_lieu_exercice TEXT,
  adresse_domicile TEXT,
  telephone VARCHAR(50),
  exoneration_flags JSONB NOT NULL DEFAULT '[]'::jsonb,
  is_nouveau_contribuable BOOLEAN NOT NULL DEFAULT FALSE,
  nb_salaries INTEGER NOT NULL DEFAULT 0,
  total_salaires_bruts NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_charges_sociales NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_irg_salaires_acquitte NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_reel_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_reel_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_reel_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_prev_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_prev_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marchandises_complementaire NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_complementaire_marchandises NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_reel_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_reel_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_reel_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_prev_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_prev_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_services_complementaire NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_complementaire_services NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_ae_reel_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_ae_reel_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_ae_reel_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_ae_prev_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_ae_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_ae_prev_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_ae_complementaire NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_complementaire_ae NUMERIC(18, 2) NOT NULL DEFAULT 0,
  is_marge_reglementee BOOLEAN NOT NULL DEFAULT FALSE,
  ca_marge_reel_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_reel_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_reel_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  marge_realisee NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_prev_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_prev_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_marge_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  marge_previsionnelle NUMERIC(18, 2) NOT NULL DEFAULT 0,
  marge_complementaire NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_complementaire_marge NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ifu_previsionnel_acquitte NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_ifu_complementaire NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_ifu_exercice NUMERIC(18, 2) NOT NULL DEFAULT 0,
  minimum_imposition NUMERIC(18, 2) NOT NULL DEFAULT 0,
  revenu_net_declare NUMERIC(18, 2) NOT NULL DEFAULT 0,
  montant_acquitte NUMERIC(18, 2) NOT NULL DEFAULT 0,
  quittance_numero VARCHAR(100),
  quittance_date DATE,
  lieu_declaration VARCHAR(255),
  date_signature DATE,
  statut VARCHAR(20) NOT NULL DEFAULT 'brouillon',
  date_depot DATE,
  submitted_at TIMESTAMPTZ,
  created_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT uq_ifu_decl_def_company_year UNIQUE (company_id, fiscal_year_id),
  CONSTRAINT chk_ifu_decl_def_statut CHECK (
    statut IN ('brouillon', 'deposee', 'validee')
  ),
  CONSTRAINT chk_ifu_decl_def_periode CHECK (
    periode_du IS NULL OR periode_au IS NULL OR periode_au >= periode_du
  )
);

CREATE INDEX IF NOT EXISTS idx_ifu_decl_def_company_id
  ON ifu_declarations_definitives (company_id);
CREATE INDEX IF NOT EXISTS idx_ifu_decl_def_fiscal_year_id
  ON ifu_declarations_definitives (fiscal_year_id);
CREATE INDEX IF NOT EXISTS idx_ifu_decl_def_annee
  ON ifu_declarations_definitives (annee);
CREATE INDEX IF NOT EXISTS idx_ifu_decl_def_statut
  ON ifu_declarations_definitives (statut);

ALTER TABLE ifu_declarations_definitives
  ADD COLUMN IF NOT EXISTS direction_wilaya VARCHAR(255),
  ADD COLUMN IF NOT EXISTS diw VARCHAR(100),
  ADD COLUMN IF NOT EXISTS recette VARCHAR(255),
  ADD COLUMN IF NOT EXISTS commune VARCHAR(150),
  ADD COLUMN IF NOT EXISTS nom_raison_sociale VARCHAR(255),
  ADD COLUMN IF NOT EXISTS activites_exercees TEXT,
  ADD COLUMN IF NOT EXISTS date_debut_activite DATE,
  ADD COLUMN IF NOT EXISTS adresse_lieu_exercice TEXT,
  ADD COLUMN IF NOT EXISTS adresse_domicile TEXT,
  ADD COLUMN IF NOT EXISTS telephone VARCHAR(50),
  ADD COLUMN IF NOT EXISTS exoneration_flags JSONB NOT NULL DEFAULT '[]'::jsonb,
  ADD COLUMN IF NOT EXISTS ca_marchandises_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ca_services_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ca_ae_reel_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ca_ae_reel_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ca_ae_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ca_ae_prev_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS is_marge_reglementee BOOLEAN NOT NULL DEFAULT FALSE,
  ADD COLUMN IF NOT EXISTS ca_marge_prev_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ca_marge_prev_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ca_marge_prev_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS ifu_previsionnel_acquitte NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS total_ifu_exercice NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS minimum_imposition NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS lieu_declaration VARCHAR(255),
  ADD COLUMN IF NOT EXISTS date_signature DATE,
  ADD COLUMN IF NOT EXISTS submitted_at TIMESTAMPTZ;

CREATE TABLE IF NOT EXISTS g50ter_declarations (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  fiscal_year_id BIGINT NOT NULL REFERENCES fiscal_years (id) ON DELETE CASCADE,
  trimestre INTEGER NOT NULL,
  annee INTEGER NOT NULL,
  salaires_imposables_t NUMERIC(18, 2) NOT NULL DEFAULT 0,
  taux_bareme VARCHAR(100) NOT NULL DEFAULT 'Barème IRG',
  montant_irg NUMERIC(18, 2) NOT NULL DEFAULT 0,
  nif VARCHAR(32),
  nin VARCHAR(32),
  article_imposition VARCHAR(64),
  code_activite VARCHAR(20),
  date_versement DATE,
  delai_limite DATE,
  quittance_numero VARCHAR(100),
  quittance_date DATE,
  lieu_declaration VARCHAR(255),
  date_signature DATE,
  receveur_signature VARCHAR(255),
  receveur_date DATE,
  statut VARCHAR(20) NOT NULL DEFAULT 'brouillon',
  created_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT uq_g50ter_company_period UNIQUE (company_id, annee, trimestre),
  CONSTRAINT chk_g50ter_trimestre CHECK (trimestre BETWEEN 1 AND 4),
  CONSTRAINT chk_g50ter_statut CHECK (
    statut IN ('brouillon', 'deposee', 'validee')
  )
);

CREATE INDEX IF NOT EXISTS idx_g50ter_company_id ON g50ter_declarations (company_id);
CREATE INDEX IF NOT EXISTS idx_g50ter_fiscal_year_id ON g50ter_declarations (fiscal_year_id);
CREATE INDEX IF NOT EXISTS idx_g50ter_annee ON g50ter_declarations (annee);
CREATE INDEX IF NOT EXISTS idx_g50ter_trimestre ON g50ter_declarations (trimestre);
CREATE INDEX IF NOT EXISTS idx_g50ter_statut ON g50ter_declarations (statut);

ALTER TABLE g50ter_declarations
  ADD COLUMN IF NOT EXISTS lieu_declaration VARCHAR(255),
  ADD COLUMN IF NOT EXISTS date_signature DATE,
  ADD COLUMN IF NOT EXISTS receveur_signature VARCHAR(255),
  ADD COLUMN IF NOT EXISTS receveur_date DATE;

CREATE TABLE IF NOT EXISTS g50_declarations (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  mois INTEGER,
  trimestre INTEGER,
  annee INTEGER NOT NULL,
  periodicite VARCHAR(20) NOT NULL,
  nif VARCHAR(32),
  nin VARCHAR(32),
  article_imposition VARCHAR(64),
  forme_juridique VARCHAR(100),
  code_activite VARCHAR(20),
  cadre1_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  e1m10_acompte_ibs NUMERIC(18, 2) NOT NULL DEFAULT 0,
  solde_liquidation_ibs NUMERIC(18, 2) NOT NULL DEFAULT 0,
  acompte_icbs NUMERIC(18, 2) NOT NULL DEFAULT 0,
  solde_liquidation_icbs NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_cadre1 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  cadre2_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  e1m30_ibs_entreprises_etrangeres NUMERIC(18, 2) NOT NULL DEFAULT 0,
  taux_e1m30 NUMERIC(8, 2) NOT NULL DEFAULT 0,
  e1m40_ibs_autres_retenues NUMERIC(18, 2) NOT NULL DEFAULT 0,
  taux_e1m40 NUMERIC(8, 2) NOT NULL DEFAULT 0,
  total_cadre2 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  cadre3_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  acompte_irg_bic_bnc NUMERIC(18, 2) NOT NULL DEFAULT 0,
  solde_liquidation_irg NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_cadre3 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  irg_retenues_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  total_cadre4 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tls_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  total_cadre5 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  droits_timbre_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  total_cadre6 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  autres_taxes_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  total_cadre7 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tva_ca_imposable_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  tva_deductions_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  tva_total_droits NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tva_total_deductions NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tva_a_payer NUMERIC(18, 2) NOT NULL DEFAULT 0,
  tva_precompte_reporter NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_cadre8 NUMERIC(18, 2) NOT NULL DEFAULT 0,
  total_a_payer NUMERIC(18, 2) NOT NULL DEFAULT 0,
  mode_paiement VARCHAR(100),
  cheque_bancaire_no VARCHAR(100),
  cheque_bancaire_agence VARCHAR(150),
  cheque_postal_no VARCHAR(100),
  montant_numeraire NUMERIC(18, 2) NOT NULL DEFAULT 0,
  quittance_numero VARCHAR(100),
  quittance_date DATE,
  lieu_declaration VARCHAR(255),
  date_signature DATE,
  statut VARCHAR(20) NOT NULL DEFAULT 'brouillon',
  observations TEXT,
  submitted_at TIMESTAMPTZ,
  created_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT chk_g50_periodicite CHECK (
    periodicite IN ('mensuel', 'trimestriel')
  ),
  CONSTRAINT chk_g50_mois CHECK (mois IS NULL OR mois BETWEEN 1 AND 12),
  CONSTRAINT chk_g50_trimestre CHECK (trimestre IS NULL OR trimestre BETWEEN 1 AND 4),
  CONSTRAINT chk_g50_statut CHECK (
    statut IN ('brouillon', 'deposee', 'validee')
  ),
  CONSTRAINT chk_g50_period_fields CHECK (
    (
      periodicite = 'mensuel'
      AND mois IS NOT NULL
      AND trimestre IS NULL
    )
    OR (
      periodicite = 'trimestriel'
      AND trimestre IS NOT NULL
      AND mois IS NULL
    )
  )
);

CREATE UNIQUE INDEX IF NOT EXISTS uq_g50_company_monthly
  ON g50_declarations (company_id, annee, mois)
  WHERE periodicite = 'mensuel';

CREATE UNIQUE INDEX IF NOT EXISTS uq_g50_company_quarterly
  ON g50_declarations (company_id, annee, trimestre)
  WHERE periodicite = 'trimestriel';

CREATE INDEX IF NOT EXISTS idx_g50_company_id ON g50_declarations (company_id);
CREATE INDEX IF NOT EXISTS idx_g50_annee ON g50_declarations (annee);
CREATE INDEX IF NOT EXISTS idx_g50_mois ON g50_declarations (mois);
CREATE INDEX IF NOT EXISTS idx_g50_trimestre ON g50_declarations (trimestre);
CREATE INDEX IF NOT EXISTS idx_g50_statut ON g50_declarations (statut);
CREATE INDEX IF NOT EXISTS idx_g50_company_periodicite
  ON g50_declarations (company_id, periodicite);

ALTER TABLE g50_declarations
  ADD COLUMN IF NOT EXISTS cadre1_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  ADD COLUMN IF NOT EXISTS cadre2_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  ADD COLUMN IF NOT EXISTS cadre3_detail JSONB NOT NULL DEFAULT '{}'::jsonb,
  ADD COLUMN IF NOT EXISTS cheque_bancaire_agence VARCHAR(150),
  ADD COLUMN IF NOT EXISTS lieu_declaration VARCHAR(255),
  ADD COLUMN IF NOT EXISTS date_signature DATE,
  ADD COLUMN IF NOT EXISTS submitted_at TIMESTAMPTZ;

CREATE TABLE IF NOT EXISTS tva_operations (
  id BIGSERIAL PRIMARY KEY,
  g50_id BIGINT NOT NULL REFERENCES g50_declarations (id) ON DELETE CASCADE,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  code VARCHAR(50) NOT NULL,
  operation_label TEXT,
  taux NUMERIC(8, 2) NOT NULL DEFAULT 0,
  ca_global NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_imposable NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ca_exonere NUMERIC(18, 2) NOT NULL DEFAULT 0,
  montant_droits NUMERIC(18, 2) NOT NULL DEFAULT 0,
  CONSTRAINT uq_tva_operations_g50_code UNIQUE (g50_id, code)
);

CREATE INDEX IF NOT EXISTS idx_tva_operations_g50_id ON tva_operations (g50_id);
CREATE INDEX IF NOT EXISTS idx_tva_operations_company_id ON tva_operations (company_id);

CREATE TABLE IF NOT EXISTS fiscal_deadlines (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  fiscal_year_id BIGINT REFERENCES fiscal_years (id) ON DELETE CASCADE,
  declaration_type VARCHAR(20) NOT NULL,
  deadline_date DATE NOT NULL,
  periode_label VARCHAR(100) NOT NULL,
  statut VARCHAR(20) NOT NULL DEFAULT 'upcoming',
  declaration_id BIGINT,
  CONSTRAINT chk_fiscal_deadlines_type CHECK (
    declaration_type IN ('GN12', 'GN12BIS', 'G50TER', 'G50')
  ),
  CONSTRAINT chk_fiscal_deadlines_statut CHECK (
    statut IN ('upcoming', 'due_soon', 'overdue', 'filed')
  )
);

CREATE INDEX IF NOT EXISTS idx_fiscal_deadlines_company_id ON fiscal_deadlines (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_deadlines_fiscal_year_id ON fiscal_deadlines (fiscal_year_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_deadlines_statut ON fiscal_deadlines (statut);
CREATE INDEX IF NOT EXISTS idx_fiscal_deadlines_declaration_type
  ON fiscal_deadlines (declaration_type);
CREATE INDEX IF NOT EXISTS idx_fiscal_deadlines_deadline_date
  ON fiscal_deadlines (company_id, deadline_date);
CREATE UNIQUE INDEX IF NOT EXISTS uq_fiscal_deadlines_company_period
  ON fiscal_deadlines (company_id, fiscal_year_id, declaration_type, periode_label);

CREATE TABLE IF NOT EXISTS fiscal_penalties (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  declaration_id BIGINT NOT NULL,
  declaration_type VARCHAR(20) NOT NULL,
  penalty_type VARCHAR(30) NOT NULL,
  base_amount NUMERIC(18, 2) NOT NULL DEFAULT 0,
  penalty_rate NUMERIC(8, 2) NOT NULL DEFAULT 0,
  penalty_amount NUMERIC(18, 2) NOT NULL DEFAULT 0,
  months_late INTEGER NOT NULL DEFAULT 0,
  calculated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT chk_fiscal_penalties_decl_type CHECK (
    declaration_type IN ('GN12', 'GN12BIS', 'G50TER', 'G50')
  ),
  CONSTRAINT chk_fiscal_penalties_type CHECK (
    penalty_type IN ('retard_10pct', 'mise_en_demeure_25pct', 'astreinte_3pct', 'neant_500da')
  )
);

CREATE INDEX IF NOT EXISTS idx_fiscal_penalties_company_id ON fiscal_penalties (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_penalties_declaration
  ON fiscal_penalties (declaration_type, declaration_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_penalties_created_at
  ON fiscal_penalties (created_at DESC);

CREATE TABLE IF NOT EXISTS fiscal_declaration_entries (
  id BIGSERIAL PRIMARY KEY,
  company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
  declaration_type VARCHAR(20) NOT NULL,
  declaration_id BIGINT NOT NULL,
  declaration_year INTEGER,
  entry_kind VARCHAR(50) NOT NULL,
  declaration_label VARCHAR(255) NOT NULL,
  period_label VARCHAR(100),
  amount NUMERIC(18, 2) NOT NULL DEFAULT 0,
  journal_entry_id BIGINT NOT NULL REFERENCES journal_entries (id) ON DELETE CASCADE,
  generated_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT chk_fiscal_declaration_entries_type CHECK (
    declaration_type IN ('GN12', 'GN12BIS', 'G50TER', 'G50')
  ),
  CONSTRAINT uq_fiscal_declaration_entries_kind UNIQUE (
    company_id,
    declaration_type,
    declaration_id,
    entry_kind
  )
);

ALTER TABLE fiscal_declaration_entries
  ADD COLUMN IF NOT EXISTS declaration_year INTEGER,
  ADD COLUMN IF NOT EXISTS entry_kind VARCHAR(50),
  ADD COLUMN IF NOT EXISTS declaration_label VARCHAR(255),
  ADD COLUMN IF NOT EXISTS period_label VARCHAR(100),
  ADD COLUMN IF NOT EXISTS amount NUMERIC(18, 2) NOT NULL DEFAULT 0,
  ADD COLUMN IF NOT EXISTS generated_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
  ADD COLUMN IF NOT EXISTS metadata JSONB NOT NULL DEFAULT '{}'::jsonb;

CREATE INDEX IF NOT EXISTS idx_fiscal_declaration_entries_company_id
  ON fiscal_declaration_entries (company_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_declaration_entries_declaration
  ON fiscal_declaration_entries (declaration_type, declaration_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_declaration_entries_year
  ON fiscal_declaration_entries (company_id, declaration_year);
CREATE INDEX IF NOT EXISTS idx_fiscal_declaration_entries_journal_entry
  ON fiscal_declaration_entries (journal_entry_id);
CREATE INDEX IF NOT EXISTS idx_fiscal_declaration_entries_created_at
  ON fiscal_declaration_entries (created_at DESC);

COMMIT;
