CREATE TABLE IF NOT EXISTS roles (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(80) NOT NULL UNIQUE,
    description VARCHAR(255) NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS permissions (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(120) NOT NULL UNIQUE,
    description VARCHAR(255) NULL
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS role_permissions (
    role_id BIGINT UNSIGNED NOT NULL,
    permission_id BIGINT UNSIGNED NOT NULL,
    PRIMARY KEY (role_id, permission_id),
    FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
    FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    role_id BIGINT UNSIGNED NOT NULL,
    email VARCHAR(190) NOT NULL UNIQUE,
    name VARCHAR(120) NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    last_login_at TIMESTAMP NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (role_id) REFERENCES roles(id)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS clients (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(190) NOT NULL,
    registration_number VARCHAR(120) NULL,
    status ENUM('active', 'inactive') NOT NULL DEFAULT 'active',
    support_email VARCHAR(190) NULL,
    support_phone VARCHAR(60) NULL,
    preferred_contact_method VARCHAR(40) NULL,
    physical_address TEXT NULL,
    postal_address TEXT NULL,
    general_notes TEXT NULL,
    created_by BIGINT UNSIGNED NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX clients_name_idx (name),
    INDEX clients_status_idx (status),
    FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS client_contacts (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    client_id BIGINT UNSIGNED NOT NULL,
    name VARCHAR(120) NOT NULL,
    email VARCHAR(190) NULL,
    phone VARCHAR(60) NULL,
    is_primary BOOLEAN NOT NULL DEFAULT FALSE,
    primary_client_id BIGINT UNSIGNED AS (IF(is_primary, client_id, NULL)) STORED,
    notes TEXT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
    INDEX contacts_client_idx (client_id),
    UNIQUE KEY one_primary_contact (primary_client_id)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS jobcard_sequences (
    sequence_year SMALLINT UNSIGNED PRIMARY KEY,
    next_sequence INT UNSIGNED NOT NULL
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS technical_information (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    client_id BIGINT UNSIGNED NOT NULL,
    category VARCHAR(80) NOT NULL,
    data_json JSON NOT NULL,
    updated_by BIGINT UNSIGNED NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
    FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL,
    UNIQUE KEY technical_client_category (client_id, category)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS credentials (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    client_id BIGINT UNSIGNED NOT NULL,
    category VARCHAR(80) NOT NULL,
    label VARCHAR(120) NOT NULL,
    username VARCHAR(190) NULL,
    secret_ciphertext TEXT NOT NULL,
    notes TEXT NULL,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_by BIGINT UNSIGNED NULL,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
    FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
    INDEX credentials_client_idx (client_id),
    INDEX credentials_category_idx (category)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS sla_agreements (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    client_id BIGINT UNSIGNED NOT NULL,
    enabled BOOLEAN NOT NULL DEFAULT TRUE,
    agreement_type VARCHAR(120) NULL,
    allocated_hours DECIMAL(10,2) NOT NULL DEFAULT 0,
    period_type ENUM('monthly', 'annual', 'custom') NOT NULL DEFAULT 'monthly',
    start_date DATE NULL,
    end_date DATE NULL,
    rollover_enabled BOOLEAN NOT NULL DEFAULT FALSE,
    notes TEXT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
    UNIQUE KEY sla_client_unique (client_id)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS jobcards (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    reference_no VARCHAR(40) NOT NULL UNIQUE,
    client_id BIGINT UNSIGNED NOT NULL,
    created_by BIGINT UNSIGNED NULL,
    priority VARCHAR(40) NOT NULL DEFAULT 'normal',
    status VARCHAR(60) NOT NULL DEFAULT 'new',
    work_requested TEXT NOT NULL,
    technician_notes TEXT NULL,
    internal_notes TEXT NULL,
    completed_at DATETIME NULL,
    closed_at DATETIME NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (client_id) REFERENCES clients(id),
    FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
    INDEX jobcards_client_idx (client_id),
    INDEX jobcards_status_idx (status),
    INDEX jobcards_created_idx (created_at)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS jobcard_assignments (
    jobcard_id BIGINT UNSIGNED NOT NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    assigned_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    assigned_by BIGINT UNSIGNED NULL,
    PRIMARY KEY (jobcard_id, user_id),
    FOREIGN KEY (jobcard_id) REFERENCES jobcards(id) ON DELETE CASCADE,
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (assigned_by) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS jobcard_status_history (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    jobcard_id BIGINT UNSIGNED NOT NULL,
    from_status VARCHAR(60) NOT NULL,
    to_status VARCHAR(60) NOT NULL,
    changed_by BIGINT UNSIGNED NULL,
    changed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (jobcard_id) REFERENCES jobcards(id) ON DELETE CASCADE,
    FOREIGN KEY (changed_by) REFERENCES users(id) ON DELETE SET NULL,
    INDEX status_history_jobcard_idx (jobcard_id, changed_at)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS time_entries (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    jobcard_id BIGINT UNSIGNED NOT NULL,
    technician_id BIGINT UNSIGNED NOT NULL,
    work_date DATE NOT NULL,
    start_time TIME NULL,
    end_time TIME NULL,
    hours DECIMAL(10,2) NOT NULL,
    notes TEXT NULL,
    counts_toward_sla BOOLEAN NOT NULL DEFAULT TRUE,
    created_by BIGINT UNSIGNED NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (jobcard_id) REFERENCES jobcards(id) ON DELETE CASCADE,
    FOREIGN KEY (technician_id) REFERENCES users(id),
    FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL,
    INDEX time_jobcard_idx (jobcard_id),
    INDEX time_date_idx (work_date)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS attachments (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    jobcard_id BIGINT UNSIGNED NOT NULL,
    original_name VARCHAR(255) NOT NULL,
    stored_name VARCHAR(255) NOT NULL UNIQUE,
    mime_type VARCHAR(120) NOT NULL,
    file_size BIGINT UNSIGNED NOT NULL,
    client_visible BOOLEAN NOT NULL DEFAULT FALSE,
    uploaded_by BIGINT UNSIGNED NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (jobcard_id) REFERENCES jobcards(id) ON DELETE CASCADE,
    FOREIGN KEY (uploaded_by) REFERENCES users(id) ON DELETE SET NULL,
    INDEX attachments_jobcard_idx (jobcard_id)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS notifications (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    type VARCHAR(80) NOT NULL,
    title VARCHAR(190) NOT NULL,
    body TEXT NULL,
    deduplication_key VARCHAR(190) NULL,
    read_at TIMESTAMP NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    UNIQUE KEY notification_dedup_idx (user_id, deduplication_key),
    INDEX notification_unread_idx (user_id, read_at, created_at)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS audit_events (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NULL,
    action VARCHAR(120) NOT NULL,
    entity_type VARCHAR(80) NOT NULL,
    entity_id BIGINT UNSIGNED NULL,
    metadata JSON NULL,
    ip_address VARCHAR(45) NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX audit_entity_idx (entity_type, entity_id),
    INDEX audit_created_idx (created_at),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB;

INSERT IGNORE INTO roles (name, description) VALUES
    ('Administrator', 'Full system access'),
    ('Accounts', 'Client, jobcard and reporting access'),
    ('Technician', 'Assigned support work access');

INSERT IGNORE INTO permissions (name, description) VALUES
    ('dashboard.view', 'View the operational dashboard'),
    ('clients.view', 'View client records'),
    ('clients.manage', 'Create and edit client records'),
    ('jobcards.view', 'View jobcards'),
    ('jobcards.manage', 'Create and update jobcards'),
    ('jobcards.assign', 'Assign technicians to jobcards'),
    ('jobcards.internal_notes', 'View and edit internal jobcard notes'),
    ('time_entries.record', 'Record technician time entries'),
    ('technical.view', 'View client technical information'),
    ('technical.manage', 'Manage client technical information'),
    ('credentials.view', 'View protected credentials'),
    ('credentials.manage', 'Manage protected credentials'),
    ('attachments.view', 'View jobcard attachments'),
    ('attachments.manage', 'Manage jobcard attachments'),
    ('notifications.view', 'View notifications'),
    ('sla.view', 'View client SLA agreements and usage'),
    ('sla.manage', 'Configure client SLA agreements'),
    ('reports.view', 'View reports'),
    ('reports.export', 'Export reports'),
    ('users.manage', 'Manage users'),
    ('roles.manage', 'Manage roles and permissions'),
    ('audit.view', 'View audit events');

INSERT IGNORE INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p WHERE r.name = 'Administrator';

INSERT IGNORE INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id FROM roles r JOIN permissions p ON p.name IN
('dashboard.view','clients.view','jobcards.view','reports.view','reports.export','sla.view')
WHERE r.name = 'Accounts';

INSERT IGNORE INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id FROM roles r JOIN permissions p ON p.name IN
('dashboard.view','clients.view','jobcards.view','jobcards.manage','time_entries.record')
WHERE r.name = 'Technician';
