-- ========================================
-- PRODUCTION DATABASE SETUP
-- ========================================
-- Ten plik tworzy całą strukturę bazy danych dla production
-- Uruchom ten skrypt w Replit Database UI -> Production Database -> SQL runner

-- Krok 1: Utwórz schematy
CREATE SCHEMA IF NOT EXISTS allegro;
CREATE SCHEMA IF NOT EXISTS shoper;
CREATE SCHEMA IF NOT EXISTS commerce;

-- Krok 2: Tabela allegro.orders
CREATE TABLE IF NOT EXISTS allegro.orders (
    id SERIAL PRIMARY KEY,
    order_id VARCHAR(255) UNIQUE NOT NULL,
    marketplace VARCHAR(50),
    seller_status VARCHAR(50),
    seller_login VARCHAR(255),
    buyer_login VARCHAR(255),
    buyer_name VARCHAR(255),
    buyer_email VARCHAR(255),
    buyer_company VARCHAR(255),
    buyer_phone VARCHAR(50),
    buyer_address VARCHAR(500),
    buyer_zip VARCHAR(20),
    buyer_city VARCHAR(100),
    buyer_country_code VARCHAR(10),
    order_date TIMESTAMP,
    payment_id VARCHAR(255),
    payment_status VARCHAR(50),
    payment_type VARCHAR(50),
    payment_provider VARCHAR(100),
    payment_amount NUMERIC(10, 2),
    payment_currency VARCHAR(10),
    delivery_method VARCHAR(255),
    delivery_amount NUMERIC(10, 2),
    delivery_currency VARCHAR(10),
    total_to_pay_amount NUMERIC(10, 2),
    total_to_pay_currency VARCHAR(10),
    buyer_notes TEXT,
    invoice_required BOOLEAN DEFAULT false,
    smart BOOLEAN DEFAULT false,
    allegro_pay BOOLEAN DEFAULT false,
    tracking_numbers TEXT[] DEFAULT '{}',
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Krok 3: Tabela allegro.order_items
CREATE TABLE IF NOT EXISTS allegro.order_items (
    id SERIAL PRIMARY KEY,
    order_id VARCHAR(255) REFERENCES allegro.orders(order_id) ON DELETE CASCADE,
    offer_id VARCHAR(255),
    offer_name VARCHAR(500),
    quantity INTEGER,
    unit_price NUMERIC(10, 2),
    total_price NUMERIC(10, 2),
    external_id VARCHAR(255),
    created_at TIMESTAMP DEFAULT NOW()
);

-- Krok 4: Tabela allegro.products
CREATE TABLE IF NOT EXISTS allegro.products (
    id SERIAL PRIMARY KEY,
    offer_id VARCHAR(255) UNIQUE NOT NULL,
    name VARCHAR(500),
    category_id VARCHAR(255),
    price NUMERIC(10, 2),
    stock INTEGER,
    ean VARCHAR(50),
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Krok 5: Tabela allegro.sync_logs
CREATE TABLE IF NOT EXISTS allegro.sync_logs (
    id SERIAL PRIMARY KEY,
    sync_type VARCHAR(50),
    status VARCHAR(50),
    message TEXT,
    created_at TIMESTAMP DEFAULT NOW()
);

-- Krok 6: Tabela shoper.orders
CREATE TABLE IF NOT EXISTS shoper.orders (
    id SERIAL PRIMARY KEY,
    shoper_order_id VARCHAR(255) UNIQUE NOT NULL,
    order_date TIMESTAMP,
    buyer_login VARCHAR(255),
    buyer_email VARCHAR(255),
    total_amount NUMERIC(10, 2),
    currency VARCHAR(10),
    payment_status VARCHAR(50),
    fulfillment_status VARCHAR(50),
    raw_data JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Krok 7: Tabela commerce.orders
CREATE TABLE IF NOT EXISTS commerce.orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    order_number INTEGER,
    order_code VARCHAR(20) GENERATED ALWAYS AS ('ORD-' || LPAD(order_number::TEXT, 6, '0')) STORED,
    source VARCHAR(20) NOT NULL,
    source_order_id VARCHAR(255) NOT NULL,
    order_date TIMESTAMP,
    status VARCHAR(50),
    buyer_login VARCHAR(255),
    buyer_email VARCHAR(255),
    buyer_company VARCHAR(255),
    buyer_first_name VARCHAR(255),
    buyer_last_name VARCHAR(255),
    buyer_phone VARCHAR(50),
    buyer_address VARCHAR(500),
    buyer_zip VARCHAR(20),
    buyer_city VARCHAR(100),
    buyer_country_code VARCHAR(10),
    payment_id VARCHAR(255),
    payment_status VARCHAR(50),
    payment_type VARCHAR(50),
    payment_provider VARCHAR(100),
    payment_amount NUMERIC(10, 2),
    payment_currency VARCHAR(10),
    delivery_method VARCHAR(255),
    delivery_amount NUMERIC(10, 2),
    delivery_currency VARCHAR(10),
    total_to_pay_amount NUMERIC(10, 2),
    total_to_pay_currency VARCHAR(10),
    buyer_notes TEXT,
    invoice_required BOOLEAN DEFAULT false,
    tracking_numbers TEXT[] DEFAULT '{}',
    raw_payload JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW(),
    UNIQUE(source_order_id, source)
);

-- Krok 8: Tabela sync_settings
CREATE TABLE IF NOT EXISTS sync_settings (
    id SERIAL PRIMARY KEY,
    platform VARCHAR(50) UNIQUE NOT NULL,
    last_sync_date TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Krok 9: Tabela allegro_connections
CREATE TABLE IF NOT EXISTS allegro_connections (
    id SERIAL PRIMARY KEY,
    access_token TEXT,
    refresh_token TEXT,
    expires_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- Krok 10: Utwórz sekwencję dla numerów zamówień
CREATE SEQUENCE IF NOT EXISTS commerce.order_number_seq START 1000;

-- Krok 11: Trigger dla Allegro -> Commerce (z podziałem imienia i nazwiska)
CREATE OR REPLACE FUNCTION public.sync_allegro_to_commerce()
RETURNS TRIGGER AS $$
DECLARE
    v_first_name VARCHAR;
    v_last_name VARCHAR;
    name_parts TEXT[];
BEGIN
    -- Rozdziel imię i nazwisko (jeśli istnieje)
    IF NEW.buyer_name IS NOT NULL THEN
        name_parts := string_to_array(TRIM(NEW.buyer_name), ' ');
        v_first_name := name_parts[1];
        IF array_length(name_parts, 1) > 1 THEN
            v_last_name := array_to_string(name_parts[2:array_length(name_parts, 1)], ' ');
        END IF;
    END IF;
    
    -- Wstaw lub zaktualizuj w commerce.orders
    INSERT INTO commerce.orders (
        id,
        source,
        source_order_id,
        order_date,
        status,
        buyer_login,
        buyer_email,
        buyer_company,
        buyer_first_name,
        buyer_last_name,
        buyer_phone,
        buyer_address,
        buyer_zip,
        buyer_city,
        buyer_country_code,
        payment_id,
        payment_status,
        payment_type,
        payment_provider,
        payment_amount,
        payment_currency,
        delivery_method,
        delivery_amount,
        delivery_currency,
        total_to_pay_amount,
        total_to_pay_currency,
        buyer_notes,
        invoice_required,
        tracking_numbers,
        raw_payload,
        created_at,
        updated_at
    ) VALUES (
        gen_random_uuid(),
        'ALLEGRO',
        NEW.order_id,
        NEW.order_date,
        NEW.seller_status,
        NEW.buyer_login,
        NEW.buyer_email,
        NEW.buyer_company,
        v_first_name,
        v_last_name,
        NEW.buyer_phone,
        NEW.buyer_address,
        NEW.buyer_zip,
        NEW.buyer_city,
        NEW.buyer_country_code,
        NEW.payment_id,
        NEW.payment_status,
        NEW.payment_type,
        NEW.payment_provider,
        NEW.payment_amount,
        NEW.payment_currency,
        NEW.delivery_method,
        NEW.delivery_amount,
        NEW.delivery_currency,
        NEW.total_to_pay_amount,
        NEW.total_to_pay_currency,
        NEW.buyer_notes,
        NEW.invoice_required,
        NEW.tracking_numbers,
        jsonb_build_object(
            'order_id', NEW.order_id,
            'marketplace', NEW.marketplace,
            'smart', NEW.smart,
            'allegro_pay', NEW.allegro_pay
        ),
        NOW(),
        NOW()
    )
    ON CONFLICT (source_order_id, source) DO UPDATE SET
        order_date = EXCLUDED.order_date,
        status = EXCLUDED.status,
        buyer_login = EXCLUDED.buyer_login,
        buyer_email = EXCLUDED.buyer_email,
        buyer_company = EXCLUDED.buyer_company,
        buyer_first_name = EXCLUDED.buyer_first_name,
        buyer_last_name = EXCLUDED.buyer_last_name,
        buyer_phone = EXCLUDED.buyer_phone,
        buyer_address = EXCLUDED.buyer_address,
        buyer_zip = EXCLUDED.buyer_zip,
        buyer_city = EXCLUDED.buyer_city,
        buyer_country_code = EXCLUDED.buyer_country_code,
        payment_id = EXCLUDED.payment_id,
        payment_status = EXCLUDED.payment_status,
        payment_type = EXCLUDED.payment_type,
        payment_provider = EXCLUDED.payment_provider,
        payment_amount = EXCLUDED.payment_amount,
        payment_currency = EXCLUDED.payment_currency,
        delivery_method = EXCLUDED.delivery_method,
        delivery_amount = EXCLUDED.delivery_amount,
        delivery_currency = EXCLUDED.delivery_currency,
        total_to_pay_amount = EXCLUDED.total_to_pay_amount,
        total_to_pay_currency = EXCLUDED.total_to_pay_currency,
        buyer_notes = EXCLUDED.buyer_notes,
        invoice_required = EXCLUDED.invoice_required,
        tracking_numbers = EXCLUDED.tracking_numbers,
        updated_at = NOW();
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS allegro_to_commerce_trigger ON allegro.orders;
CREATE TRIGGER allegro_to_commerce_trigger
AFTER INSERT OR UPDATE ON allegro.orders
FOR EACH ROW
EXECUTE FUNCTION public.sync_allegro_to_commerce();

-- Krok 12: Trigger dla Shoper -> Commerce
CREATE OR REPLACE FUNCTION public.sync_shoper_to_commerce()
RETURNS TRIGGER AS $$
DECLARE
    v_raw jsonb;
    v_billing_address jsonb;
    v_delivery_address jsonb;
    v_first_name VARCHAR;
    v_last_name VARCHAR;
    v_phone VARCHAR;
    v_company VARCHAR;
    v_street VARCHAR;
    v_zip VARCHAR;
    v_city VARCHAR;
    v_country_code VARCHAR;
    v_delivery_cost NUMERIC;
BEGIN
    v_raw := NEW.raw_data;
    
    -- Wyciągnij dane z billing_address
    IF v_raw->>'billing_address' IS NOT NULL THEN
        v_billing_address := (v_raw->>'billing_address')::jsonb;
        v_first_name := v_billing_address->>'firstname';
        v_last_name := v_billing_address->>'lastname';
        v_phone := v_billing_address->>'phone';
        v_company := v_billing_address->>'company';
    END IF;
    
    -- Wyciągnij dane z delivery_address
    IF v_raw->>'delivery_address' IS NOT NULL THEN
        v_delivery_address := (v_raw->>'delivery_address')::jsonb;
        v_street := v_delivery_address->>'street1';
        v_zip := v_delivery_address->>'postcode';
        v_city := v_delivery_address->>'city';
        v_country_code := v_delivery_address->>'country_code';
    END IF;
    
    v_delivery_cost := (v_raw->>'shipping_cost')::numeric;
    
    -- Wstaw lub zaktualizuj w commerce.orders
    INSERT INTO commerce.orders (
        id,
        source,
        source_order_id,
        order_date,
        status,
        buyer_login,
        buyer_email,
        buyer_company,
        buyer_first_name,
        buyer_last_name,
        buyer_phone,
        buyer_address,
        buyer_zip,
        buyer_city,
        buyer_country_code,
        payment_status,
        payment_type,
        payment_amount,
        payment_currency,
        delivery_amount,
        delivery_currency,
        total_to_pay_amount,
        total_to_pay_currency,
        buyer_notes,
        invoice_required,
        raw_payload,
        created_at,
        updated_at
    ) VALUES (
        gen_random_uuid(),
        'SHOPER',
        NEW.shoper_order_id,
        NEW.order_date,
        NEW.fulfillment_status,
        NEW.buyer_login,
        NEW.buyer_email,
        v_company,
        v_first_name,
        v_last_name,
        v_phone,
        v_street,
        v_zip,
        v_city,
        v_country_code,
        NEW.payment_status,
        CASE 
            WHEN (v_raw->>'payment_id')::int = 2 THEN 'ONLINE'
            ELSE 'CASH_ON_DELIVERY'
        END,
        NEW.total_amount,
        NEW.currency,
        v_delivery_cost,
        NEW.currency,
        NEW.total_amount,
        NEW.currency,
        v_raw->>'notes',
        false,
        v_raw,
        NOW(),
        NOW()
    )
    ON CONFLICT (source_order_id, source) DO UPDATE SET
        order_date = EXCLUDED.order_date,
        status = EXCLUDED.status,
        buyer_login = EXCLUDED.buyer_login,
        buyer_email = EXCLUDED.buyer_email,
        buyer_company = EXCLUDED.buyer_company,
        buyer_first_name = EXCLUDED.buyer_first_name,
        buyer_last_name = EXCLUDED.buyer_last_name,
        buyer_phone = EXCLUDED.buyer_phone,
        buyer_address = EXCLUDED.buyer_address,
        buyer_zip = EXCLUDED.buyer_zip,
        buyer_city = EXCLUDED.buyer_city,
        buyer_country_code = EXCLUDED.buyer_country_code,
        payment_status = EXCLUDED.payment_status,
        payment_type = EXCLUDED.payment_type,
        payment_amount = EXCLUDED.payment_amount,
        delivery_amount = EXCLUDED.delivery_amount,
        total_to_pay_amount = EXCLUDED.total_to_pay_amount,
        buyer_notes = EXCLUDED.buyer_notes,
        raw_payload = EXCLUDED.raw_payload,
        updated_at = NOW();
    
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS shoper_to_commerce_trigger ON shoper.orders;
CREATE TRIGGER shoper_to_commerce_trigger
AFTER INSERT OR UPDATE ON shoper.orders
FOR EACH ROW
EXECUTE FUNCTION public.sync_shoper_to_commerce();

-- Krok 13: Trigger dla auto-increment order_number
CREATE OR REPLACE FUNCTION commerce.set_order_number()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.order_number IS NULL THEN
        NEW.order_number := nextval('commerce.order_number_seq');
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS set_order_number_trigger ON commerce.orders;
CREATE TRIGGER set_order_number_trigger
BEFORE INSERT ON commerce.orders
FOR EACH ROW
EXECUTE FUNCTION commerce.set_order_number();

-- Gotowe! 🎉
