-- ============================================================
-- Warehouse Management Database - Init Script (PostgreSQL)
-- Based on WareHouseDB.md specification
-- ============================================================

-- ============================================================
-- ENUM Types
-- ============================================================
CREATE TYPE container_type_enum AS ENUM ('empty_box', 'tray', 'paper_box', 'plastic_box', 'bag', 'other');
CREATE TYPE component_item_status_enum AS ENUM ('normal', 'damaged', 'long_unused', 'expired', 'pending_inspection');
CREATE TYPE invoice_type_enum AS ENUM ('import', 'export');
CREATE TYPE invoice_status_enum AS ENUM ('draft', 'pending', 'approved', 'completed', 'cancelled');
CREATE TYPE transaction_type_enum AS ENUM ('import', 'export', 'adjustment', 'transfer');

-- ============================================================
-- Trigger function: auto-update updated_at
-- ============================================================
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- ============================================================
-- 1. warehouses (Kho)
-- ============================================================
CREATE TABLE warehouses (
    id          BIGSERIAL       PRIMARY KEY,
    name        VARCHAR(255)    NOT NULL,
    description TEXT,
    address     VARCHAR(500),
    created_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER trg_warehouses_updated_at
    BEFORE UPDATE ON warehouses
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 2. rooms (Phòng)
-- ============================================================
CREATE TABLE rooms (
    id           BIGSERIAL       PRIMARY KEY,
    warehouse_id BIGINT          NOT NULL REFERENCES warehouses(id),
    name         VARCHAR(255)    NOT NULL,
    description  TEXT,
    created_at   TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at   TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER trg_rooms_updated_at
    BEFORE UPDATE ON rooms
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 3. cabinets (Tủ)
-- ============================================================
CREATE TABLE cabinets (
    id          BIGSERIAL       PRIMARY KEY,
    room_id     BIGINT          NOT NULL REFERENCES rooms(id),
    name        VARCHAR(255)    NOT NULL,
    description TEXT,
    created_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER trg_cabinets_updated_at
    BEFORE UPDATE ON cabinets
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 4. shelves (Tầng / Kệ)
-- ============================================================
CREATE TABLE shelves (
    id          BIGSERIAL       PRIMARY KEY,
    cabinet_id  BIGINT          NOT NULL REFERENCES cabinets(id),
    name        VARCHAR(255)    NOT NULL,
    level_index INT             NOT NULL,
    description TEXT,
    created_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER trg_shelves_updated_at
    BEFORE UPDATE ON shelves
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 5. containers (Vật chứa)
-- ============================================================
CREATE TABLE containers (
    id             BIGSERIAL            PRIMARY KEY,
    shelf_id       BIGINT               NOT NULL REFERENCES shelves(id),
    name           VARCHAR(255)         NOT NULL,
    container_type container_type_enum  NOT NULL,
    description    TEXT,
    max_capacity   INT,
    metadata       JSONB,
    created_at     TIMESTAMPTZ          NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at     TIMESTAMPTZ          NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER trg_containers_updated_at
    BEFORE UPDATE ON containers
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 6. component_types (Loại linh kiện)
-- ============================================================
CREATE TABLE component_types (
    id          BIGSERIAL       PRIMARY KEY,
    name        VARCHAR(255)    NOT NULL,
    description TEXT,
    metadata    JSONB,
    created_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uk_component_types_name UNIQUE (name)
);
CREATE TRIGGER trg_component_types_updated_at
    BEFORE UPDATE ON component_types
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 7. components (Linh kiện)
-- ============================================================
CREATE TABLE components (
    id                BIGSERIAL       PRIMARY KEY,
    component_type_id BIGINT          NOT NULL REFERENCES component_types(id),
    name              VARCHAR(255)    NOT NULL,
    description       TEXT,
    unit              VARCHAR(50)     NOT NULL DEFAULT 'cái',
    total_quantity    INT             NOT NULL DEFAULT 0,
    min_quantity      INT             NOT NULL DEFAULT 0,
    metadata          JSONB,
    created_at        TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at        TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER trg_components_updated_at
    BEFORE UPDATE ON components
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 8. component_codes (Mã linh kiện)
-- ============================================================
CREATE TABLE component_codes (
    id           BIGSERIAL       PRIMARY KEY,
    component_id BIGINT          NOT NULL REFERENCES components(id),
    code         VARCHAR(255)    NOT NULL,
    code_type    VARCHAR(100),
    is_primary   BOOLEAN         NOT NULL DEFAULT FALSE,
    metadata     JSONB,
    created_at   TIMESTAMPTZ     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uk_component_codes_code_type UNIQUE (code, code_type)
);

-- ============================================================
-- 9. component_items (Linh kiện tại từng vị trí)
-- ============================================================
CREATE TABLE component_items (
    id           BIGSERIAL                     PRIMARY KEY,
    component_id BIGINT                        NOT NULL REFERENCES components(id),
    container_id BIGINT                        NOT NULL REFERENCES containers(id),
    quantity     INT                           NOT NULL DEFAULT 0,
    status       component_item_status_enum    NOT NULL DEFAULT 'normal',
    metadata     JSONB,
    created_at   TIMESTAMPTZ                   NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at   TIMESTAMPTZ                   NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uk_component_items_comp_cont_status UNIQUE (component_id, container_id, status)
);
CREATE TRIGGER trg_component_items_updated_at
    BEFORE UPDATE ON component_items
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 10. component_status_history (Lịch sử thay đổi tình trạng)
-- ============================================================
CREATE TABLE component_status_history (
    id                BIGSERIAL                     PRIMARY KEY,
    component_item_id BIGINT                        NOT NULL REFERENCES component_items(id),
    old_status        component_item_status_enum,
    new_status        component_item_status_enum    NOT NULL,
    changed_quantity  INT,
    note              TEXT,
    changed_by        VARCHAR(255),
    changed_at        TIMESTAMPTZ                   NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- ============================================================
-- 11. invoice_configs (Cấu hình hóa đơn mẫu)
-- ============================================================
CREATE TABLE invoice_configs (
    id          BIGSERIAL           PRIMARY KEY,
    name        VARCHAR(255)        NOT NULL,
    type        invoice_type_enum   NOT NULL,
    description TEXT,
    is_active   BOOLEAN             NOT NULL DEFAULT TRUE,
    metadata    JSONB,
    created_at  TIMESTAMPTZ         NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMPTZ         NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TRIGGER trg_invoice_configs_updated_at
    BEFORE UPDATE ON invoice_configs
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 12. invoice_config_items (Chi tiết cấu hình hóa đơn)
-- ============================================================
CREATE TABLE invoice_config_items (
    id                BIGSERIAL   PRIMARY KEY,
    invoice_config_id BIGINT      NOT NULL REFERENCES invoice_configs(id),
    component_id      BIGINT      NOT NULL REFERENCES components(id),
    required_quantity INT         NOT NULL,
    allow_alternative BOOLEAN     NOT NULL DEFAULT FALSE,
    priority_order    INT         NOT NULL DEFAULT 0,
    note              TEXT,
    metadata          JSONB,
    CONSTRAINT uk_invoice_config_items_config_comp UNIQUE (invoice_config_id, component_id)
);

-- ============================================================
-- 13. alternative_components (Linh kiện thay thế)
-- ============================================================
CREATE TABLE alternative_components (
    id                       BIGSERIAL       PRIMARY KEY,
    invoice_config_item_id   BIGINT          NOT NULL REFERENCES invoice_config_items(id),
    alternative_component_id BIGINT          NOT NULL REFERENCES components(id),
    conversion_ratio         DECIMAL(10,2)   NOT NULL DEFAULT 1.00,
    priority                 INT             NOT NULL DEFAULT 0,
    note                     TEXT,
    metadata                 JSONB,
    CONSTRAINT uk_alternative_components_item_alt UNIQUE (invoice_config_item_id, alternative_component_id)
);

-- ============================================================
-- 14. invoices (Hóa đơn nhập/xuất)
-- ============================================================
CREATE TABLE invoices (
    id                BIGSERIAL            PRIMARY KEY,
    invoice_code      VARCHAR(100)         NOT NULL,
    type              invoice_type_enum    NOT NULL,
    status            invoice_status_enum  NOT NULL DEFAULT 'draft',
    invoice_config_id BIGINT               REFERENCES invoice_configs(id),
    total_items       INT                  NOT NULL DEFAULT 0,
    note              TEXT,
    created_by        VARCHAR(255),
    approved_by       VARCHAR(255),
    completed_at      TIMESTAMPTZ,
    created_at        TIMESTAMPTZ          NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at        TIMESTAMPTZ          NOT NULL DEFAULT CURRENT_TIMESTAMP,
    metadata          JSONB,
    CONSTRAINT uk_invoices_invoice_code UNIQUE (invoice_code)
);
CREATE TRIGGER trg_invoices_updated_at
    BEFORE UPDATE ON invoices
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- 15. invoice_items (Chi tiết hóa đơn)
-- ============================================================
CREATE TABLE invoice_items (
    id                    BIGSERIAL   PRIMARY KEY,
    invoice_id            BIGINT      NOT NULL REFERENCES invoices(id),
    component_id          BIGINT      NOT NULL REFERENCES components(id),
    original_component_id BIGINT      REFERENCES components(id),
    required_quantity     INT         NOT NULL,
    actual_quantity       INT         NOT NULL DEFAULT 0,
    is_substituted        BOOLEAN     NOT NULL DEFAULT FALSE,
    is_short              BOOLEAN     NOT NULL DEFAULT FALSE,
    shortage_quantity     INT         NOT NULL DEFAULT 0,
    note                  TEXT,
    metadata              JSONB,
    CONSTRAINT uk_invoice_items_invoice_comp UNIQUE (invoice_id, component_id)
);

-- ============================================================
-- 16. invoice_item_locations (Vị trí xuất/nhập cho từng item)
-- ============================================================
CREATE TABLE invoice_item_locations (
    id              BIGSERIAL   PRIMARY KEY,
    invoice_item_id BIGINT      NOT NULL REFERENCES invoice_items(id),
    container_id    BIGINT      NOT NULL REFERENCES containers(id),
    quantity        INT         NOT NULL
);

-- ============================================================
-- 17. invoice_status_history (Lịch sử trạng thái hóa đơn)
-- ============================================================
CREATE TABLE invoice_status_history (
    id         BIGSERIAL    PRIMARY KEY,
    invoice_id BIGINT       NOT NULL REFERENCES invoices(id),
    old_status VARCHAR(50),
    new_status VARCHAR(50)  NOT NULL,
    changed_by VARCHAR(255),
    note       TEXT,
    changed_at TIMESTAMPTZ  NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- ============================================================
-- 18. stock_transactions (Lịch sử nhập xuất kho)
-- ============================================================
CREATE TABLE stock_transactions (
    id                BIGSERIAL               PRIMARY KEY,
    invoice_id        BIGINT                  NOT NULL REFERENCES invoices(id),
    component_id      BIGINT                  NOT NULL REFERENCES components(id),
    container_id      BIGINT                  NOT NULL REFERENCES containers(id),
    transaction_type  transaction_type_enum   NOT NULL,
    quantity          INT                     NOT NULL,
    balance_after     INT,
    note              TEXT,
    created_by        VARCHAR(255),
    created_at        TIMESTAMPTZ             NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    full_name VARCHAR(100),
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by VARCHAR(50)
);

-- Bảng Roles: Lưu các vai trò (admin, editor, viewer...)
CREATE TABLE roles (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(50) UNIQUE NOT NULL,
    description VARCHAR(255),
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by VARCHAR(50)
);

-- Bảng Permissions: Lưu các quyền hạn (read, write, delete...)
CREATE TABLE permissions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(100) UNIQUE NOT NULL,
    description VARCHAR(255),
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    created_by VARCHAR(50)
);

-- Bảng user_roles: Liên kết user với role (N-N)
CREATE TABLE user_roles (
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
    assigned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (user_id, role_id)
);

-- Bảng role_permissions: Liên kết role với permission (N-N)
CREATE TABLE role_permissions (
    role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
    permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
    assigned_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (role_id, permission_id)
);


-- ============================================================
-- Indexes
-- ============================================================

-- Comment: Tạo index cho việc tìm kiếm nhanh (tùy chọn)
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_roles_name ON roles(name);
-- Index cho truy vấn nhanh
CREATE INDEX idx_user_roles_user_id ON user_roles(user_id);
CREATE INDEX idx_user_roles_role_id ON user_roles(role_id);
CREATE INDEX idx_role_permissions_role_id ON role_permissions(role_id);
CREATE INDEX idx_role_permissions_permission_id ON role_permissions(permission_id);

-- Tìm linh kiện theo vị trí
CREATE INDEX idx_component_items_component ON component_items(component_id);
CREATE INDEX idx_component_items_container ON component_items(container_id);
CREATE INDEX idx_component_items_status ON component_items(status);

-- Tìm mã linh kiện
CREATE INDEX idx_component_codes_code ON component_codes(code);
CREATE INDEX idx_component_codes_component ON component_codes(component_id);

-- Thống kê hóa đơn theo thời gian
CREATE INDEX idx_invoices_type_status ON invoices(type, status);
CREATE INDEX idx_invoices_created_at ON invoices(created_at);
CREATE INDEX idx_invoices_type_created ON invoices(type, created_at);

-- Thống kê giao dịch kho
CREATE INDEX idx_stock_transactions_component_date ON stock_transactions(component_id, created_at);
CREATE INDEX idx_stock_transactions_type_date ON stock_transactions(transaction_type, created_at);
CREATE INDEX idx_stock_transactions_invoice ON stock_transactions(invoice_id);

-- Tìm vị trí container (theo cấu trúc phân cấp)
CREATE INDEX idx_containers_shelf ON containers(shelf_id);
CREATE INDEX idx_shelves_cabinet ON shelves(cabinet_id);
CREATE INDEX idx_cabinets_room ON cabinets(room_id);
CREATE INDEX idx_rooms_warehouse ON rooms(warehouse_id);


-- ============================================================
-- Seed: Default permissions (theo module)
-- ============================================================

-- Warehouse module
INSERT INTO permissions (name, description) VALUES
    ('warehouse:create', 'Tạo kho mới'),
    ('warehouse:read', 'Xem thông tin kho'),
    ('warehouse:update', 'Cập nhật kho'),
    ('warehouse:delete', 'Xóa kho');

-- Room module
INSERT INTO permissions (name, description) VALUES
    ('room:create', 'Tạo phòng mới'),
    ('room:read', 'Xem thông tin phòng'),
    ('room:update', 'Cập nhật phòng'),
    ('room:delete', 'Xóa phòng');

-- Cabinet module
INSERT INTO permissions (name, description) VALUES
    ('cabinet:create', 'Tạo tủ mới'),
    ('cabinet:read', 'Xem thông tin tủ'),
    ('cabinet:update', 'Cập nhật tủ'),
    ('cabinet:delete', 'Xóa tủ');

-- Shelf module
INSERT INTO permissions (name, description) VALUES
    ('shelf:create', 'Tạo kệ mới'),
    ('shelf:read', 'Xem thông tin kệ'),
    ('shelf:update', 'Cập nhật kệ'),
    ('shelf:delete', 'Xóa kệ');

-- Container module
INSERT INTO permissions (name, description) VALUES
    ('container:create', 'Tạo vật chứa mới'),
    ('container:read', 'Xem thông tin vật chứa'),
    ('container:update', 'Cập nhật vật chứa'),
    ('container:delete', 'Xóa vật chứa');

-- Component Type module
INSERT INTO permissions (name, description) VALUES
    ('component_type:create', 'Tạo loại linh kiện mới'),
    ('component_type:read', 'Xem loại linh kiện'),
    ('component_type:update', 'Cập nhật loại linh kiện'),
    ('component_type:delete', 'Xóa loại linh kiện');

-- Component module
INSERT INTO permissions (name, description) VALUES
    ('component:create', 'Tạo linh kiện mới'),
    ('component:read', 'Xem thông tin linh kiện'),
    ('component:update', 'Cập nhật linh kiện'),
    ('component:delete', 'Xóa linh kiện');

-- Invoice module
INSERT INTO permissions (name, description) VALUES
    ('invoice:create', 'Tạo hóa đơn mới'),
    ('invoice:read', 'Xem thông tin hóa đơn'),
    ('invoice:update', 'Cập nhật hóa đơn'),
    ('invoice:delete', 'Xóa hóa đơn'),
    ('invoice:approve', 'Duyệt hóa đơn');

-- Stock module
INSERT INTO permissions (name, description) VALUES
    ('stock:import', 'Nhập kho'),
    ('stock:export', 'Xuất kho'),
    ('stock:adjust', 'Điều chỉnh tồn kho'),
    ('stock:transfer', 'Chuyển kho'),
    ('stock:read', 'Xem báo cáo tồn kho');

-- User & RBAC module
INSERT INTO permissions (name, description) VALUES
    ('user:create', 'Tạo người dùng mới'),
    ('user:read', 'Xem thông tin người dùng'),
    ('user:update', 'Cập nhật người dùng'),
    ('user:delete', 'Xóa người dùng'),
    ('role:manage', 'Quản lý vai trò và quyền hạn');

-- Seed: SYS_ADMIN role
INSERT INTO roles (name, description, created_by) VALUES
    ('SYS_ADMIN', 'Quản trị viên hệ thống - toàn quyền', 'system');

-- Gán TẤT CẢ permissions cho SYS_ADMIN
INSERT INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id
FROM roles r
CROSS JOIN permissions p
WHERE r.name = 'SYS_ADMIN';