-- ==========================================================
-- DMS v0.5.0
-- Database v5.1 - Trigger (Complete + Business-rule Checks)
-- Server: Container Station on QNAPQNAP TS-473A
-- Database service: MariaDB 10.11
-- database ui: phpmyadmin 5-apache
-- backend sevice: node.js
-- frontend sevice: next.js
-- reverse proxy: nginx 1.27-alpine
-- cron service: n8n
-- scripts: alpine:3.20
-- Notes:
-- ==========================================================

SET NAMES utf8mb4;
SET time_zone = '+07:00';
/* -----------------------------------------------------------
   1) CORRESPONDENCES
   - Normalize & require fields
   - Auto-set root_id on first issue
   - Guard root_id modification
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_cor_bi_normalize;
DELIMITER $$
CREATE TRIGGER trg_cor_bi_normalize
BEFORE INSERT ON correspondences
FOR EACH ROW
BEGIN
  SET NEW.correspondence_number = TRIM(NEW.correspondence_number);
  SET NEW.title                  = TRIM(NEW.title);
  SET NEW.keywords               = NULLIF(TRIM(NEW.keywords), '');
  SET NEW.revision               = NULLIF(TRIM(NEW.revision), '');
  SET NEW.is_internal_communication = IFNULL(NEW.is_internal_communication, 0);

  IF NEW.project_id IS NULL OR NEW.correspondence_type_id IS NULL OR NEW.correspondence_status_id IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='project_id/type_id/status_id is required';
  END IF;
  IF NEW.correspondence_number IS NULL OR NEW.correspondence_number='' THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='correspondence_number is required';
  END IF;

  /* ถ้าเป็น first issue (root ยังไม่ระบุ) ให้ยอมให้ revision ว่าง (จะ set root หลัง insert) */
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_cor_bu_normalize;
DELIMITER $$
CREATE TRIGGER trg_cor_bu_normalize
BEFORE UPDATE ON correspondences
FOR EACH ROW
BEGIN
  SET NEW.correspondence_number = TRIM(NEW.correspondence_number);
  SET NEW.title                  = TRIM(NEW.title);
  SET NEW.keywords               = NULLIF(TRIM(NEW.keywords), '');
  SET NEW.revision               = NULLIF(TRIM(NEW.revision), '');
  SET NEW.is_internal_communication = IFNULL(NEW.is_internal_communication, 0);

  /* ไม่อนุญาตเปลี่ยน root_id ตรง ๆ */
  IF NEW.root_id <> OLD.root_id THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='root_id is immutable';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_cor_ai_set_root;
DELIMITER $$
CREATE TRIGGER trg_cor_ai_set_root
AFTER INSERT ON correspondences
FOR EACH ROW
BEGIN
  IF NEW.root_id IS NULL THEN
    UPDATE correspondences SET root_id = NEW.corr_id WHERE corr_id = NEW.corr_id;
  END IF;
END$$
DELIMITER ;

/* กันลบ root ที่มีลูก (เสริมจาก FK RESTRICT) */
DROP TRIGGER IF EXISTS trg_cor_bd_no_delete_root_with_children;
DELIMITER $$
CREATE TRIGGER trg_cor_bd_no_delete_root_with_children
BEFORE DELETE ON correspondences
FOR EACH ROW
BEGIN
  IF EXISTS (SELECT 1 FROM correspondences WHERE root_id = OLD.corr_id AND corr_id <> OLD.corr_id) THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Cannot delete root correspondence with existing revisions';
  END IF;
END$$
DELIMITER ;

/* -----------------------------------------------------------
   2) CORRESPONDENCE CC RECIPIENTS
   - บังคับ org ที่ CC ต้องเป็น party ของ project นั้น
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_corcc_bi_guard_party;
DELIMITER $$
CREATE TRIGGER trg_corcc_bi_guard_party
BEFORE INSERT ON correspondence_cc_recipients
FOR EACH ROW
BEGIN
  DECLARE v_project_id INT;
  SELECT project_id INTO v_project_id FROM correspondences WHERE corr_id = NEW.corr_id;
  IF v_project_id IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Correspondence not found';
  END IF;

  IF NOT EXISTS (
    SELECT 1 FROM project_parties
    WHERE project_id = v_project_id AND org_id = NEW.org_id AND deleted_at IS NULL
  ) THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='CC org is not in project parties';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_corcc_bu_guard_party;
DELIMITER $$
CREATE TRIGGER trg_corcc_bu_guard_party
BEFORE UPDATE ON correspondence_cc_recipients
FOR EACH ROW
BEGIN
  DECLARE v_project_id INT;
  SELECT project_id INTO v_project_id FROM correspondences WHERE corr_id = NEW.corr_id;
  IF v_project_id IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Correspondence not found';
  END IF;

  IF NOT EXISTS (
    SELECT 1 FROM project_parties
    WHERE project_id = v_project_id AND org_id = NEW.org_id AND deleted_at IS NULL
  ) THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='CC org is not in project parties';
  END IF;
END$$
DELIMITER ;

/* -----------------------------------------------------------
   3) CORRESPONDENCE REFERENCES
   - กัน self-link ทั้ง insert/update
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_correfl_bi_guard_self;
DELIMITER $$
CREATE TRIGGER trg_correfl_bi_guard_self
BEFORE INSERT ON correspondence_references
FOR EACH ROW
BEGIN
  IF NEW.src_corr_id = NEW.tgt_corr_id THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Cannot reference a correspondence to itself';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_correfl_bu_guard_self;
DELIMITER $$
CREATE TRIGGER trg_correfl_bu_guard_self
BEFORE UPDATE ON correspondence_references
FOR EACH ROW
BEGIN
  IF NEW.src_corr_id = NEW.tgt_corr_id THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Cannot reference a correspondence to itself';
  END IF;
END$$
DELIMITER ;

/* -----------------------------------------------------------
   4) TECHNICALDOCS
   - Normalize
   - ตั้ง original_id=id เมื่อเป็นฉบับแรก
   - บังคับ original_id (ถ้ามี) ต้องอยู่โปรเจ็กต์เดียวกัน
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_tdoc_bi_normalize;
DELIMITER $$
CREATE TRIGGER trg_tdoc_bi_normalize
BEFORE INSERT ON technicaldocs
FOR EACH ROW
BEGIN
  DECLARE v_orig_proj INT;

  SET NEW.title    = TRIM(NEW.title);
  SET NEW.revision = NULLIF(TRIM(NEW.revision), '');
  SET NEW.pdf_path = NULLIF(TRIM(NEW.pdf_path), '');

  IF NEW.project_id IS NULL OR NEW.document_type_id IS NULL OR NEW.status_code_id IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='project_id/document_type_id/status_code_id is required';
  END IF;
  IF NEW.revision IS NULL OR NEW.revision='' THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='technicaldoc revision is required';
  END IF;

  SET v_orig_proj = NULL;
  IF NEW.original_id IS NOT NULL AND NEW.original_id <> 0 THEN
    SELECT project_id INTO v_orig_proj FROM technicaldocs WHERE id = NEW.original_id;
    IF v_orig_proj IS NULL THEN
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='original_id not found';
    END IF;
    IF v_orig_proj <> NEW.project_id THEN
      SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='original and new revision must be in the same project';
    END IF;
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_tdoc_bu_normalize;
DELIMITER $$
CREATE TRIGGER trg_tdoc_bu_normalize
BEFORE UPDATE ON technicaldocs
FOR EACH ROW
BEGIN
  SET NEW.title    = TRIM(NEW.title);
  SET NEW.revision = NULLIF(TRIM(NEW.revision), '');
  SET NEW.pdf_path = NULLIF(TRIM(NEW.pdf_path), '');

  /* Guard: ไม่ให้ย้าย revision ไป original อื่น/โปรเจ็กต์อื่น */
  IF NEW.original_id <> OLD.original_id THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='original_id is immutable';
  END IF;
  IF NEW.project_id <> OLD.project_id THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='project_id is immutable for a doc family';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_tdoc_ai_set_original;
DELIMITER $$
CREATE TRIGGER trg_tdoc_ai_set_original
AFTER INSERT ON technicaldocs
FOR EACH ROW
BEGIN
  IF NEW.original_id IS NULL OR NEW.original_id = 0 THEN
    UPDATE technicaldocs SET original_id = NEW.id WHERE id = NEW.id;
  END IF;
END$$
DELIMITER ;

/* -----------------------------------------------------------
   5) RFA ITEMS
   - บังคับ header ต้องเป็นชนิด RFA
   - บังคับ project ของ header กับ technicaldoc ต้องตรงกัน
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_rfa_items_bi_guard;
DELIMITER $$
CREATE TRIGGER trg_rfa_items_bi_guard
BEFORE INSERT ON rfa_items
FOR EACH ROW
BEGIN
  DECLARE v_type_code VARCHAR(20);
  DECLARE v_hdr_proj INT;
  DECLARE v_doc_proj INT;

  SELECT t.type_code, c.project_id
    INTO v_type_code, v_hdr_proj
  FROM correspondences c
  JOIN correspondence_types t ON t.type_id = c.correspondence_type_id
  WHERE c.corr_id = NEW.rfa_corr_id;

  IF v_type_code IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='RFA header not found';
  END IF;
  IF v_type_code <> 'RFA' THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='rfa_corr_id must be a correspondence of type RFA';
  END IF;

  SELECT project_id INTO v_doc_proj FROM technicaldocs WHERE id = NEW.technical_doc_id;
  IF v_doc_proj IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='technical document not found';
  END IF;

  IF v_hdr_proj <> v_doc_proj THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='RFA header and technicaldoc must be in the same project';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_rfa_items_bu_guard;
DELIMITER $$
CREATE TRIGGER trg_rfa_items_bu_guard
BEFORE UPDATE ON rfa_items
FOR EACH ROW
BEGIN
  SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Update on rfa_items is not allowed; delete and re-insert';
END$$
DELIMITER ;

/* -----------------------------------------------------------
   6) TRANSMITTAL ITEMS
   - บังคับ header เป็น TRANSMITTAL
   - ห้ามแนบตัวเอง
   - บังคับ project ตรงกัน (header ↔ item)
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_tra_items_bi_guard;
DELIMITER $$
CREATE TRIGGER trg_tra_items_bi_guard
BEFORE INSERT ON transmittal_items
FOR EACH ROW
BEGIN
  DECLARE v_type_code VARCHAR(20);
  DECLARE v_hdr_proj INT;
  DECLARE v_item_proj INT;

  IF NEW.transmittal_corr_id = NEW.item_corr_id THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='transmittal cannot include itself as an item';
  END IF;

  SELECT t.type_code, c.project_id
    INTO v_type_code, v_hdr_proj
  FROM correspondences c
  JOIN correspondence_types t ON t.type_id = c.correspondence_type_id
  WHERE c.corr_id = NEW.transmittal_corr_id;

  IF v_type_code IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Transmittal header not found';
  END IF;
  IF v_type_code <> 'TRANSMITTAL' THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='transmittal_corr_id must be type TRANSMITTAL';
  END IF;

  SELECT project_id INTO v_item_proj FROM correspondences WHERE corr_id = NEW.item_corr_id;
  IF v_item_proj IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='item correspondence not found';
  END IF;

  IF v_hdr_proj <> v_item_proj THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Transmittal header and item must be in the same project';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_tra_items_bu_guard;
DELIMITER $$
CREATE TRIGGER trg_tra_items_bu_guard
BEFORE UPDATE ON transmittal_items
FOR EACH ROW
BEGIN
  SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Update on transmittal_items is not allowed; delete and re-insert';
END$$
DELIMITER ;

/* -----------------------------------------------------------
   7) PROJECT_PARTIES
   - Normalize role
   - Guard <= 1 CONTRACTOR ต่อ project (error message ชัดเจน)
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_pp_bi_guard;
DELIMITER $$
CREATE TRIGGER trg_pp_bi_guard
BEFORE INSERT ON project_parties
FOR EACH ROW
BEGIN
  SET NEW.role = UPPER(NEW.role);

  IF NEW.role = 'CONTRACTOR' AND
     EXISTS (SELECT 1 FROM project_parties
             WHERE project_id = NEW.project_id
               AND role = 'CONTRACTOR'
               AND deleted_at IS NULL) THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='This project already has a CONTRACTOR';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_pp_bu_guard;
DELIMITER $$
CREATE TRIGGER trg_pp_bu_guard
BEFORE UPDATE ON project_parties
FOR EACH ROW
BEGIN
  SET NEW.role = UPPER(NEW.role);

  IF NEW.role = 'CONTRACTOR' AND
     EXISTS (SELECT 1 FROM project_parties
             WHERE project_id = NEW.project_id
               AND role = 'CONTRACTOR'
               AND deleted_at IS NULL
               AND NOT (org_id = OLD.org_id AND role = 'CONTRACTOR')) THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='This project already has a CONTRACTOR';
  END IF;
END$$
DELIMITER ;

/* -----------------------------------------------------------
   8) GLOBAL_DEFAULT_ROLES
   - role ต้องตรงกับ organizations.primary_role
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_gdr_bi_match_org_primary;
DELIMITER $$
CREATE TRIGGER trg_gdr_bi_match_org_primary
BEFORE INSERT ON global_default_roles
FOR EACH ROW
BEGIN
  DECLARE v_primary VARCHAR(20);
  SELECT primary_role INTO v_primary FROM organizations WHERE org_id = NEW.org_id;
  IF v_primary IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Organization not found for global_default_roles';
  END IF;
  IF NEW.role <> v_primary THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='global_default_roles.role must match organizations.primary_role';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_gdr_bu_match_org_primary;
DELIMITER $$
CREATE TRIGGER trg_gdr_bu_match_org_primary
BEFORE UPDATE ON global_default_roles
FOR EACH ROW
BEGIN
  DECLARE v_primary VARCHAR(20);
  SELECT primary_role INTO v_primary FROM organizations WHERE org_id = NEW.org_id;
  IF v_primary IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Organization not found for global_default_roles';
  END IF;
  IF NEW.role <> v_primary THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='global_default_roles.role must match organizations.primary_role';
  END IF;
END$$
DELIMITER ;

/* -----------------------------------------------------------
   9) CONTRACT DRAWINGS (normalized)
   - Normalize fields
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_cdwg_bi_normalize;
DELIMITER $$
CREATE TRIGGER trg_cdwg_bi_normalize
BEFORE INSERT ON contract_dwg
FOR EACH ROW
BEGIN
  SET NEW.condwg_no = TRIM(NEW.condwg_no);
  SET NEW.title     = NULLIF(TRIM(NEW.title), '');

  IF NEW.project_id IS NULL OR NEW.sub_cat_id IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='project_id and sub_cat_id are required for contract_dwg';
  END IF;
  IF NEW.condwg_no IS NULL OR NEW.condwg_no='' THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='condwg_no is required';
  END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_cdwg_bu_normalize;
DELIMITER $$
CREATE TRIGGER trg_cdwg_bu_normalize
BEFORE UPDATE ON contract_dwg
FOR EACH ROW
BEGIN
  SET NEW.condwg_no = TRIM(NEW.condwg_no);
  SET NEW.title     = NULLIF(TRIM(NEW.title), '');
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_cdwg_cat_bi_norm;
DELIMITER $$
CREATE TRIGGER trg_cdwg_cat_bi_norm
BEFORE INSERT ON contract_dwg_cat
FOR EACH ROW
BEGIN
  SET NEW.cat_name = TRIM(NEW.cat_name);
  IF NEW.cat_name IS NULL OR NEW.cat_name='' THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='cat_name is required';
  END IF;
END$$
DELIMITER ;

/* -----------------------------------------------------------
   10) CIRCULATION USERS
   - Normalize 0/1 flags
   -----------------------------------------------------------*/
DROP TRIGGER IF EXISTS trg_cir_users_bi_flags;
DELIMITER $$
CREATE TRIGGER trg_cir_users_bi_flags
BEFORE INSERT ON cir_users
FOR EACH ROW
BEGIN
  SET NEW.is_main   = IFNULL(NEW.is_main, 0);
  SET NEW.is_action = IFNULL(NEW.is_action, 0);
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS trg_cir_users_bu_flags;
DELIMITER $$
CREATE TRIGGER trg_cir_users_bu_flags
BEFORE UPDATE ON cir_users
FOR EACH ROW
BEGIN
  SET NEW.is_main   = IFNULL(NEW.is_main, 0);
  SET NEW.is_action = IFNULL(NEW.is_action, 0);
END$$
DELIMITER ;



/* ===========================================================
   contract_dwg_cat (Category)
   =========================================================== */

DROP TRIGGER IF EXISTS trg_cat_before_insert;
DROP TRIGGER IF EXISTS trg_cat_before_update;
DROP TRIGGER IF EXISTS trg_cat_before_delete;

DROP TRIGGER IF EXISTS trg_subcat_before_insert;
DROP TRIGGER IF EXISTS trg_subcat_before_update;
DROP TRIGGER IF EXISTS trg_subcat_before_delete;

DROP TRIGGER IF EXISTS trg_map_before_insert;
DROP TRIGGER IF EXISTS trg_map_before_update;
DROP TRIGGER IF EXISTS trg_map_before_delete;

DROP TRIGGER IF EXISTS trg_volume_before_insert;
DROP TRIGGER IF EXISTS trg_volume_before_update;
DROP TRIGGER IF EXISTS trg_volume_before_delete;

DROP TRIGGER IF EXISTS trg_dwg_before_insert;
DROP TRIGGER IF EXISTS trg_dwg_before_update;
DROP TRIGGER IF EXISTS trg_dwg_before_delete;

DELIMITER $$

/* ===========================================================
   contract_dwg_cat (Category)
   =========================================================== */
CREATE TRIGGER trg_cat_before_insert
BEFORE INSERT ON contract_dwg_cat
FOR EACH ROW
BEGIN
  -- normalize ชื่อ/โค้ด
  SET NEW.cat_name = TRIM(NEW.cat_name);
  IF NEW.cat_code IS NOT NULL THEN
    SET NEW.cat_code = TRIM(NEW.cat_code);
  END IF;

  -- audit
  SET NEW.created_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_cat_before_update
BEFORE UPDATE ON contract_dwg_cat
FOR EACH ROW
BEGIN
  DECLARE v_map_cnt INT DEFAULT 0;
  -- normalize ชื่อ/โค้ด
  IF NEW.cat_name IS NOT NULL THEN
    SET NEW.cat_name = TRIM(NEW.cat_name);
  END IF;
  IF NEW.cat_code IS NOT NULL THEN
    SET NEW.cat_code = TRIM(NEW.cat_code);
  END IF;

  -- บล็อกการย้าย project_id หากมีการอ้างอิงใน mapping
  IF NEW.project_id <> OLD.project_id THEN
    SELECT COUNT(*) INTO v_map_cnt
    FROM contract_dwg_subcat_cat_map m
    WHERE m.project_id = OLD.project_id
      AND m.cat_id = OLD.cat_id;
    IF v_map_cnt > 0 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Cannot change category project_id: mappings exist in subcat↔cat map';
    END IF;
  END IF;

  -- audit ถ้ามีคอลัมน์ updated_at)
  SET NEW.updated_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_cat_before_delete
BEFORE DELETE ON contract_dwg_cat
FOR EACH ROW
BEGIN
  -- กันลบ cat ถ้ายังมี mapping อยู่
  DECLARE v_map_cnt INT DEFAULT 0;
  SELECT COUNT(*) INTO v_map_cnt
  FROM contract_dwg_subcat_cat_map m
  WHERE m.project_id = OLD.project_id
    AND m.cat_id = OLD.cat_id;

  IF v_map_cnt > 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Cannot delete category: mapped by sub-categories in this project';
  END IF;
END$$

/* ===========================================================
   contract_dwg_sub_cat (Sub-Category)
   =========================================================== */
CREATE TRIGGER trg_subcat_before_insert
BEFORE INSERT ON contract_dwg_sub_cat
FOR EACH ROW
BEGIN
  SET NEW.sub_cat_name = TRIM(NEW.sub_cat_name);
  IF NEW.sub_cat_code IS NOT NULL THEN
    SET NEW.sub_cat_code = TRIM(NEW.sub_cat_code);
  END IF;

  SET NEW.created_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_subcat_before_update
BEFORE UPDATE ON contract_dwg_sub_cat
FOR EACH ROW
BEGIN
  DECLARE v_map_cnt INT DEFAULT 0;
  DECLARE v_dwg_cnt INT DEFAULT 0;
  IF NEW.sub_cat_name IS NOT NULL THEN
    SET NEW.sub_cat_name = TRIM(NEW.sub_cat_name);
  END IF;
  IF NEW.sub_cat_code IS NOT NULL THEN
    SET NEW.sub_cat_code = TRIM(NEW.sub_cat_code);
  END IF;

  -- บล็อกการย้าย project_id หากมีการอ้างอิง (ทั้ง mapping และ drawings)
  IF NEW.project_id <> OLD.project_id THEN
    SELECT COUNT(*) INTO v_map_cnt
    FROM contract_dwg_subcat_cat_map m
    WHERE m.project_id = OLD.project_id
      AND m.sub_cat_id = OLD.sub_cat_id;

    SELECT COUNT(*) INTO v_dwg_cnt
    FROM contract_dwg d
    WHERE d.project_id = OLD.project_id
      AND d.sub_cat_id = OLD.sub_cat_id;

    IF v_map_cnt > 0 OR v_dwg_cnt > 0 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Cannot change sub-category project_id: drawings or mappings exist';
    END IF;
  END IF;

  SET NEW.updated_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_subcat_before_delete
BEFORE DELETE ON contract_dwg_sub_cat
FOR EACH ROW
BEGIN
  DECLARE v_dwg_cnt INT DEFAULT 0;
  DECLARE v_map_cnt INT DEFAULT 0;

  SELECT COUNT(*) INTO v_dwg_cnt
  FROM contract_dwg d
  WHERE d.project_id = OLD.project_id
    AND d.sub_cat_id = OLD.sub_cat_id;

  SELECT COUNT(*) INTO v_map_cnt
  FROM contract_dwg_subcat_cat_map m
  WHERE m.project_id = OLD.project_id
    AND m.sub_cat_id = OLD.sub_cat_id;

  IF v_dwg_cnt > 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Cannot delete sub-category: drawings exist in this sub-category';
  END IF;

  IF v_map_cnt > 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Cannot delete sub-category: it is mapped to categories';
  END IF;
END$$

/* ===========================================================
   contract_dwg_subcat_cat_map (Mapping: SubCat ↔ Cat)
   - same-project guard
   =========================================================== */
CREATE TRIGGER trg_map_before_insert
BEFORE INSERT ON contract_dwg_subcat_cat_map
FOR EACH ROW
BEGIN
  DECLARE v_cnt INT DEFAULT 0;

  -- sub_cat ต้องอยู่ใน project เดียวกัน
  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_sub_cat sc
  WHERE sc.sub_cat_id = NEW.sub_cat_id
    AND sc.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid sub_cat_id: must belong to the same project (map)';
  END IF;

  -- cat ต้องอยู่ใน project เดียวกัน
  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_cat c
  WHERE c.cat_id = NEW.cat_id
    AND c.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid cat_id: must belong to the same project (map)';
  END IF;
END$$

CREATE TRIGGER trg_map_before_update
BEFORE UPDATE ON contract_dwg_subcat_cat_map
FOR EACH ROW
BEGIN
  DECLARE v_cnt INT DEFAULT 0;

  -- ไม่อนุญาตให้ย้าย project_id แบบข้ามโปรเจกต์
  IF NEW.project_id <> OLD.project_id THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Changing project_id on mapping is not allowed';
  END IF;

  -- ตรวจซ้ำว่า sub_cat/cat ยังอยู่ใน project เดิม
  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_sub_cat sc
  WHERE sc.sub_cat_id = NEW.sub_cat_id
    AND sc.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid sub_cat_id after update: must be same project';
  END IF;

  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_cat c
  WHERE c.cat_id = NEW.cat_id
    AND c.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid cat_id after update: must be same project';
  END IF;
END$$

CREATE TRIGGER trg_map_before_delete
BEFORE DELETE ON contract_dwg_subcat_cat_map
FOR EACH ROW
BEGIN
  -- ปกติอนุญาตให้ลบ mapping ได้อิสระ (ไม่มี FK ลูกต่อ)
  -- ถ้าต้องการบังคับนโยบายพิเศษ ค่อยเพิ่ม logic ที่นี่
END$$

/* ===========================================================
   contract_dwg_volume (Volume)
   =========================================================== */
CREATE TRIGGER trg_volume_before_insert
BEFORE INSERT ON contract_dwg_volume
FOR EACH ROW
BEGIN
  SET NEW.volume_code = TRIM(NEW.volume_code);
  IF NEW.volume_name IS NOT NULL THEN
    SET NEW.volume_name = TRIM(NEW.volume_name);
  END IF;

  SET NEW.created_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_volume_before_update
BEFORE UPDATE ON contract_dwg_volume
FOR EACH ROW
BEGIN
  DECLARE v_dwg_cnt INT DEFAULT 0;
  IF NEW.volume_code IS NOT NULL THEN
    SET NEW.volume_code = TRIM(NEW.volume_code);
  END IF;
  IF NEW.volume_name IS NOT NULL THEN
    SET NEW.volume_name = TRIM(NEW.volume_name);
  END IF;

  -- บล็อกการย้าย project_id หากมี drawings อ้างอยู่
  IF NEW.project_id <> OLD.project_id THEN  
    SELECT COUNT(*) INTO v_dwg_cnt
    FROM contract_dwg d
    WHERE d.project_id = OLD.project_id
      AND d.volume_id = OLD.volume_id;

    IF v_dwg_cnt > 0 THEN
      SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Cannot change volume project_id: drawings exist in this volume';
    END IF;
  END IF;

  SET NEW.updated_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_volume_before_delete
BEFORE DELETE ON contract_dwg_volume
FOR EACH ROW
BEGIN
  DECLARE v_dwg_cnt INT DEFAULT 0;
  SELECT COUNT(*) INTO v_dwg_cnt
  FROM contract_dwg d
  WHERE d.project_id = OLD.project_id
    AND d.volume_id = OLD.volume_id;

  IF v_dwg_cnt > 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Cannot delete volume: drawings exist in this volume';
  END IF;
END$$

/* ===========================================================
   contract_dwg (Drawings)
   =========================================================== */
CREATE TRIGGER trg_dwg_before_insert
BEFORE INSERT ON contract_dwg
FOR EACH ROW
BEGIN
  DECLARE v_cnt INT DEFAULT 0;

  -- normalize
  SET NEW.condwg_no = TRIM(NEW.condwg_no);
  IF NEW.title IS NOT NULL THEN
    SET NEW.title = TRIM(NEW.title);
  END IF;
  IF NEW.remark IS NOT NULL THEN
    SET NEW.remark = TRIM(NEW.remark);
  END IF;

  -- guard: sub_cat within same project
  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_sub_cat sc
  WHERE sc.sub_cat_id = NEW.sub_cat_id
    AND sc.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid sub_cat_id: must belong to same project';
  END IF;

  -- guard: volume within same project
  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_volume v
  WHERE v.volume_id = NEW.volume_id
    AND v.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid volume_id: must belong to same project';
  END IF;

  SET NEW.created_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_dwg_before_update
BEFORE UPDATE ON contract_dwg
FOR EACH ROW
BEGIN
  DECLARE v_cnt INT DEFAULT 0;

  -- normalize
  IF NEW.condwg_no IS NOT NULL THEN
    SET NEW.condwg_no = TRIM(NEW.condwg_no);
  END IF;
  IF NEW.title IS NOT NULL THEN
    SET NEW.title = TRIM(NEW.title);
  END IF;
  IF NEW.remark IS NOT NULL THEN
    SET NEW.remark = TRIM(NEW.remark);
  END IF;

  -- ไม่อนุญาตให้ย้าย project_id แบบ cross-project
  IF NEW.project_id <> OLD.project_id THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Changing drawing project_id is not allowed';
  END IF;

  -- guard: sub_cat still in same project
  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_sub_cat sc
  WHERE sc.sub_cat_id = NEW.sub_cat_id
    AND sc.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid sub_cat_id after update: must be same project';
  END IF;

  -- guard: volume still in same project
  SELECT COUNT(*) INTO v_cnt
  FROM contract_dwg_volume v
  WHERE v.volume_id = NEW.volume_id
    AND v.project_id = NEW.project_id;
  IF v_cnt = 0 THEN
    SIGNAL SQLSTATE '45000'
      SET MESSAGE_TEXT = 'Invalid volume_id after update: must be same project';
  END IF;

  SET NEW.updated_at = CURRENT_TIMESTAMP;
END$$

CREATE TRIGGER trg_dwg_before_delete
BEFORE DELETE ON contract_dwg
FOR EACH ROW
BEGIN
  -- ปกติอนุญาตให้ลบได้ (ขึ้นกับ FK อื่น ๆ ถ้ามี)
  -- ถ้ามีนโยบายพิเศษ ให้เพิ่ม logic ตรวจสอบที่นี่
END$$

DELIMITER ;

-- 2) ทริกเกอร์บังคับกฎธุรกิจ
-- technical_doc_id ต้องเป็น DWG เท่านั้น
-- โปรเจ็กต์ของ technicaldoc กับ contract_dwg ต้อง ตรงกัน
-- กันข้อมูลผิดกฎตอน INSERT
DROP TRIGGER IF EXISTS trg_scd_bi_guard;
DELIMITER $$
CREATE TRIGGER trg_scd_bi_guard
BEFORE INSERT ON dwgdoc_contract_dwg
FOR EACH ROW
BEGIN
  DECLARE v_doc_proj INT;
  DECLARE v_doc_type_code VARCHAR(20);
  DECLARE v_dwg_proj INT;

  /* 1) ตรวจว่า technical_doc เป็น DWG และมีอยู่จริง */
  SELECT t.project_id, dt.code
    INTO v_doc_proj, v_doc_type_code
  FROM technicaldocs t
  JOIN document_types dt ON dt.document_types_id = t.document_type_id
  WHERE t.id = NEW.technical_doc_id;

  IF v_doc_proj IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='technical_doc not found';
  END IF;
  IF v_doc_type_code <> 'DWG' THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='technical_doc must be type DWG';
  END IF;

  /* 2) ตรวจว่า contract_dwg อยู่โปรเจ็กต์เดียวกัน */
  SELECT project_id INTO v_dwg_proj FROM contract_dwg WHERE condwg_id = NEW.condwg_id;
  IF v_dwg_proj IS NULL THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='contract_dwg not found';
  END IF;
  IF v_dwg_proj <> v_doc_proj THEN
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='DWG doc and contract_dwg must be in the same project';
  END IF;
END$$
DELIMITER ;

-- ไม่อนุญาต UPDATE คีย์ (ลบแล้ว insert ใหม่แทน)
DROP TRIGGER IF EXISTS trg_scd_bu_block_update;
DELIMITER $$
CREATE TRIGGER trg_scd_bu_block_update
BEFORE UPDATE ON dwgdoc_contract_dwg
FOR EACH ROW
BEGIN
  SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Update not allowed; delete then insert';
END$$
DELIMITER ;

/* ===========================================================
   END OF TRIGGERS PACK
   ===========================================================*/

