-- Company Finance Database Schema
-- PostgreSQL 15+
-- Created: 2026-03-08

-- Drop existing database if exists and create new one
DROP DATABASE IF EXISTS company_finance_db;
CREATE DATABASE company_finance_db
    WITH 
    OWNER = postgres
    ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.UTF-8'
    LC_CTYPE = 'en_US.UTF-8'
    TABLESPACE = pg_default
    CONNECTION LIMIT = -1
    IS_TEMPLATE = False;

-- Connect to the new database
\c company_finance_db;

-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- ============================================
-- 1. Users Table (假设已存在，这里创建简化版本)
-- ============================================
CREATE TABLE IF NOT EXISTS users (
    user_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    full_name_zh VARCHAR(100),
    full_name_th VARCHAR(100),
    full_name_en VARCHAR(100),
    role VARCHAR(50) NOT NULL DEFAULT 'user',
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- ============================================
-- 2. Product Categories Table (商品分类表)
-- ============================================
CREATE TABLE product_categories (
    category_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    category_code VARCHAR(20) UNIQUE NOT NULL,
    name_zh VARCHAR(100) NOT NULL,
    name_th VARCHAR(100),
    name_en VARCHAR(100),
    description_zh TEXT,
    description_th TEXT,
    description_en TEXT,
    parent_category_id UUID REFERENCES product_categories(category_id) ON DELETE SET NULL,
    sort_order INTEGER DEFAULT 0,
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- ============================================
-- 3. Products Table (商品表)
-- ============================================
CREATE TABLE products (
    product_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    product_code VARCHAR(50) UNIQUE NOT NULL,
    sku VARCHAR(50) UNIQUE,
    name_zh VARCHAR(200) NOT NULL,
    name_th VARCHAR(200),
    name_en VARCHAR(200),
    description_zh TEXT,
    description_th TEXT,
    description_en TEXT,
    category_id UUID REFERENCES product_categories(category_id) ON DELETE SET NULL,
    unit_price NUMERIC(15,2) NOT NULL DEFAULT 0.00,
    currency VARCHAR(3) DEFAULT 'CNY',
    unit_type VARCHAR(50) DEFAULT 'piece',
    specifications JSONB,
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- ============================================
-- 4. Projects Table (项目表)
-- ============================================
CREATE TABLE projects (
    project_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    project_code VARCHAR(50) UNIQUE NOT NULL,
    name_zh VARCHAR(200) NOT NULL,
    name_th VARCHAR(200),
    name_en VARCHAR(200),
    description_zh TEXT,
    description_th TEXT,
    description_en TEXT,
    client_name_zh VARCHAR(200),
    client_name_th VARCHAR(200),
    client_name_en VARCHAR(200),
    contract_number VARCHAR(100),
    contract_amount NUMERIC(15,2) NOT NULL DEFAULT 0.00,
    currency VARCHAR(3) DEFAULT 'CNY',
    start_date DATE,
    end_date DATE,
    status VARCHAR(50) DEFAULT 'planning' CHECK (status IN ('planning', 'in_progress', 'completed', 'cancelled', 'on_hold')),
    project_manager_id UUID REFERENCES users(user_id) ON DELETE SET NULL,
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- ============================================
-- 5. Payment Nodes Table (付款节点表)
-- ============================================
CREATE TABLE payment_nodes (
    node_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    project_id UUID REFERENCES projects(project_id) ON DELETE CASCADE,
    node_code VARCHAR(50) NOT NULL,
    name_zh VARCHAR(200) NOT NULL,
    name_th VARCHAR(200),
    name_en VARCHAR(200),
    description_zh TEXT,
    description_th TEXT,
    description_en TEXT,
    planned_date DATE NOT NULL,
    actual_date DATE,
    planned_amount NUMERIC(15,2) NOT NULL DEFAULT 0.00,
    actual_amount NUMERIC(15,2),
    currency VARCHAR(3) DEFAULT 'CNY',
    node_type VARCHAR(50) DEFAULT 'payment' CHECK (node_type IN ('payment', 'receipt', 'milestone')),
    status VARCHAR(50) DEFAULT 'pending' CHECK (status IN ('pending', 'confirmed', 'completed', 'cancelled', 'delayed')),
    sort_order INTEGER DEFAULT 0,
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(project_id, node_code)
);

-- ============================================
-- 6. Payment Records Table (收付款记录表)
-- ============================================
CREATE TABLE payment_records (
    record_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    node_id UUID REFERENCES payment_nodes(node_id) ON DELETE CASCADE,
    record_type VARCHAR(50) NOT NULL CHECK (record_type IN ('payment', 'receipt')),
    amount NUMERIC(15,2) NOT NULL DEFAULT 0.00,
    currency VARCHAR(3) DEFAULT 'CNY',
    exchange_rate NUMERIC(10,6) DEFAULT 1.000000,
    converted_amount NUMERIC(15,2),
    payment_date DATE NOT NULL,
    payment_method VARCHAR(50) DEFAULT 'bank_transfer' CHECK (payment_method IN ('bank_transfer', 'cash', 'check', 'credit_card', 'digital_wallet')),
    reference_number VARCHAR(100),
    bank_name VARCHAR(200),
    account_number VARCHAR(100),
    payer_name VARCHAR(200),
    payee_name VARCHAR(200),
    description TEXT,
    status VARCHAR(50) DEFAULT 'pending' CHECK (status IN ('pending', 'processing', 'completed', 'failed', 'cancelled')),
    attachment_urls TEXT[],
    verified_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    verified_at TIMESTAMP WITH TIME ZONE,
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

-- ============================================
-- 7. Exchange Rates Table (汇率表)
-- ============================================
CREATE TABLE exchange_rates (
    rate_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    base_currency VARCHAR(3) NOT NULL,
    target_currency VARCHAR(3) NOT NULL,
    exchange_rate NUMERIC(10,6) NOT NULL,
    effective_date DATE NOT NULL,
    source VARCHAR(100) DEFAULT 'manual',
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(base_currency, target_currency, effective_date)
);

-- ============================================
-- 8. Language Configs Table (多语言配置表)
-- ============================================
CREATE TABLE language_configs (
    config_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    config_key VARCHAR(100) NOT NULL,
    module VARCHAR(50) NOT NULL,
    value_zh TEXT NOT NULL,
    value_th TEXT,
    value_en TEXT,
    description TEXT,
    sort_order INTEGER DEFAULT 0,
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(config_key, module)
);

-- ============================================
-- 9. Project Products Table (项目商品关联表)
-- ============================================
CREATE TABLE project_products (
    project_product_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    project_id UUID REFERENCES projects(project_id) ON DELETE CASCADE,
    product_id UUID REFERENCES products(product_id) ON DELETE CASCADE,
    quantity INTEGER NOT NULL DEFAULT 1,
    unit_price NUMERIC(15,2) NOT NULL DEFAULT 0.00,
    currency VARCHAR(3) DEFAULT 'CNY',
    total_amount NUMERIC(15,2) GENERATED ALWAYS AS (quantity * unit_price) STORED,
    description TEXT,
    is_active BOOLEAN DEFAULT TRUE,
    created_by UUID REFERENCES users(user_id) ON DELETE SET NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(project_id, product_id)
);

-- ============================================
-- INDEXES
-- ============================================

-- Users indexes
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_role ON users(role);

-- Product categories indexes
CREATE INDEX idx_product_categories_code ON product_categories(category_code);
CREATE INDEX idx_product_categories_parent ON product_categories(parent_category_id);
CREATE INDEX idx_product_categories_active ON product_categories(is_active);

-- Products indexes
CREATE INDEX idx_products_code ON products(product_code);
CREATE INDEX idx_products_sku ON products(sku);
CREATE INDEX idx_products_category ON products(category_id);
CREATE INDEX idx_products_active ON products(is_active);
CREATE INDEX idx_products_price ON products(unit_price);

-- Projects indexes
CREATE INDEX idx_projects_code ON projects(project_code);
CREATE INDEX idx_projects_status ON projects(status);
CREATE INDEX idx_projects_manager ON projects(project_manager_id);
CREATE INDEX idx_projects_dates ON projects(start_date, end_date);
CREATE INDEX idx_projects_active ON projects(is_active);

-- Payment nodes indexes
CREATE INDEX idx_payment_nodes_project ON payment_nodes(project_id);
CREATE INDEX idx_payment_nodes_code ON payment_nodes(node_code);
CREATE INDEX idx_payment_nodes_dates ON payment_nodes(planned_date, actual_date);
CREATE INDEX idx_payment_nodes_status ON payment_nodes(status);
CREATE INDEX idx_payment_nodes_type ON payment_nodes(node_type);

-- Payment records indexes
CREATE INDEX idx_payment_records_node ON payment_records(node_id);
CREATE INDEX idx_payment_records_type ON payment_records(record_type);
CREATE INDEX idx_payment_records_date ON payment_records(payment_date);
CREATE INDEX idx_payment_records_status ON payment_records(status);
CREATE INDEX idx_payment_records_method ON payment_records(payment_method);

-- Exchange rates indexes
CREATE INDEX idx_exchange_rates_currencies ON exchange_rates(base_currency, target_currency);
CREATE INDEX idx_exchange_rates_date ON exchange_rates(effective_date);
CREATE INDEX idx_exchange_rates_active ON exchange_rates(is_active);

-- Language configs indexes
CREATE INDEX idx_language_configs_key ON language_configs(config_key);
CREATE INDEX idx_language_configs_module ON language_configs(module);
CREATE INDEX idx_language_configs_active ON language_configs(is_active);

-- Project products indexes
CREATE INDEX idx_project_products_project ON project_products(project_id);
CREATE INDEX idx_project_products_product ON project_products(product_id);
CREATE INDEX idx_project_products_active ON project_products(is_active);

-- ============================================
-- VIEWS
-- ============================================

-- View: 项目概览视图
CREATE OR REPLACE VIEW project_overview AS
SELECT 
    p.project_id,
    p.project_code,
    p.name_zh as project_name_zh,
    p.name_en as project_name_en,
    p.contract_amount,
    p.currency,
    p.start_date,
    p.end_date,
    p.status as project_status,
    u.full_name_zh as project_manager_name,
    COUNT(DISTINCT pp.product_id) as product_count,
    COUNT(DISTINCT pn.node_id) as payment_node_count,
    COALESCE(SUM(pr.amount), 0) as total_payments,
    COALESCE(SUM(CASE WHEN pr.record_type = 'receipt' THEN pr.amount ELSE 0 END), 0) as total_receipts,
    COALESCE(SUM(CASE WHEN pr.record_type = 'payment' THEN pr.amount ELSE 0 END), 0) as total_expenses
FROM projects p
LEFT JOIN users u ON p.project_manager_id = u.user_id
LEFT JOIN project_products pp ON p.project_id = pp.project_id
LEFT JOIN payment_nodes pn ON p.project_id = pn.project_id
LEFT JOIN payment_records pr ON pn.node_id = pr.node_id
WHERE p.is_active = TRUE
GROUP BY p.project_id, p.project_code, p.name_zh, p.name_en, p.contract_amount, p.currency, 
         p.start_date, p.end_date, p.status, u.full_name_zh;

-- View: 付款节点详情视图
CREATE OR REPLACE VIEW payment_node_details AS
SELECT 
    pn.node_id,
    pn.project_id,
    p.project_code,
    p.name_zh as project_name_zh,
    pn.node_code,
    pn.name_zh as node_name_zh,
    pn.planned_date,
    pn.actual_date,
    pn.planned_amount,
    pn.actual_amount,
    pn.currency,
    pn.node_type,
    pn.status as node_status,
    COUNT(pr.record_id) as record_count,
    COALESCE(SUM(pr.amount), 0) as total_recorded_amount,
    CASE 
        WHEN pn.node_type = 'payment' THEN '支出'
        WHEN pn.node_type = 'receipt' THEN '收入'
        ELSE '里程碑'
    END as node_type_cn
FROM payment_nodes pn
JOIN projects p ON pn.project_id = p.project_id
LEFT JOIN payment_records pr ON pn.node_id = pr.node_id AND pr.is_active = TRUE
WHERE pn.is_active = TRUE
GROUP BY pn.node_id, pn.project_id, p.project_code, p.name_zh, pn.node_code, pn.name_zh,
         pn.planned_date, pn.actual_date, pn.planned_amount, pn.actual_amount, pn.currency,
         pn.node_type, pn.status;

-- View: 商品分类树视图
CREATE OR REPLACE VIEW product_category_tree AS
WITH RECURSIVE category_tree AS (
    SELECT 
        category_id,
        category_code,
        name_zh,
        name_en,
        parent_category_id,
        1 as level,
        ARRAY[category_code] as path_codes,
        ARRAY[name_zh] as path_names
    FROM product_categories
    WHERE parent_category_id IS NULL AND is_active = TRUE
    
    UNION ALL
    
    SELECT 
        c.category_id,
        c.category_code,
        c.name_zh,
        c.name_en,
        c.parent_category_id,
        ct.level + 1,
        ct.path_codes || c.category_code,
        ct.path_names || c.name_zh
    FROM product_categories c
    JOIN category_tree ct ON c.parent_category_id = ct.category_id
    WHERE c.is_active = TRUE
)
SELECT 
    category_id,
    category_code,
    name_zh,
    name_en,
    parent_category_id,
    level,
    array_to_string(path_codes, ' > ') as full_path_code,
    array_to_string(path_names, ' > ') as full_path_name
FROM category_tree
ORDER BY path_codes;

-- View: 汇率最新视图
CREATE OR REPLACE VIEW latest_exchange_rates AS
SELECT DISTINCT ON (base_currency, target_currency)
    rate_id,
    base_currency,
    target_currency,
    exchange_rate,
    effective_date,
    source,
    created_at
FROM exchange_rates
WHERE is_active = TRUE
ORDER BY base_currency, target_currency, effective_date DESC;

-- ============================================
-- FUNCTIONS AND TRIGGERS
-- ============================================

-- Function to update updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ language 'plpgsql';

-- Create triggers for all tables with updated_at column
DO $$ 
DECLARE 
    table_name text;
BEGIN
    FOR table_name IN 
        SELECT tablename FROM pg_tables 
        WHERE schemaname = 'public' 
        AND tablename IN (
            'users', 'product_categories', 'products', 'projects', 
            'payment_nodes', 'payment_records', 'exchange_rates', 
            'language_configs', 'project_products'
        )
    LOOP
        EXECUTE format('
            DROP TRIGGER IF EXISTS update_%s_updated_at ON %s;
            CREATE TRIGGER update_%s_updated_at
            BEFORE UPDATE ON %s
            FOR EACH ROW
            EXECUTE FUNCTION update_updated_at_column();
        ', table_name, table_name, table_name, table_name);
    END LOOP;
END $$;

-- Function to calculate project financial summary
CREATE OR REPLACE FUNCTION calculate_project_financial_summary(project_uuid UUID)
RETURNS TABLE(
    total_contract_amount NUMERIC,
    total_planned_payments NUMERIC,
    total_actual_payments NUMERIC,
    total_planned_receipts NUMERIC,
    total_actual_receipts NUMERIC,
    balance NUMERIC
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        COALESCE(p.contract_amount,