CREATE TABLE IF NOT EXISTS storeLocation (
    storeId BIGINT AUTO_INCREMENT PRIMARY KEY,
    storeName VARCHAR(100) NOT NULL,
    address VARCHAR(255) NOT NULL,
    phone VARCHAR(20) NOT NULL,
    email VARCHAR(100) NOT NULL,
    imageUrl VARCHAR(500) NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NULL UNIQUE,
    password VARCHAR(255) NULL,
    email VARCHAR(100) NULL UNIQUE,
    firstName VARCHAR(50) NOT NULL,
    lastName VARCHAR(50) NOT NULL,
    fullName VARCHAR(100) NULL,
    phone VARCHAR(20) NULL UNIQUE,
    avatarUrl VARCHAR(255) NULL,
    role VARCHAR(20) NOT NULL,
    staffRole VARCHAR(50) NULL,
    primaryStoreId BIGINT NULL,
    loyaltyPoints INT NOT NULL DEFAULT 0,
    active BOOLEAN NOT NULL DEFAULT TRUE,
    tokenVersion INT NOT NULL DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_users_primary_store FOREIGN KEY (primaryStoreId) REFERENCES storeLocation(storeId) ON DELETE SET NULL,
    INDEX idx_users_primary_store (primaryStoreId),
    INDEX idx_users_role (role),
    INDEX idx_users_name (lastName, firstName)
);

CREATE TABLE IF NOT EXISTS supplier (
    supId BIGINT AUTO_INCREMENT PRIMARY KEY,
    supCompany VARCHAR(100) NOT NULL,
    supContactFirstName VARCHAR(50) NOT NULL,
    supContactLastName VARCHAR(50) NOT NULL,
    supEmail VARCHAR(100) NOT NULL,
    supPhone VARCHAR(20) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS category (
    categoryId BIGINT AUTO_INCREMENT PRIMARY KEY,
    categoryName VARCHAR(100) NOT NULL,
    categoryType VARCHAR(50) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT uq_category_name_type UNIQUE (categoryName, categoryType)
);

CREATE TABLE IF NOT EXISTS service (
    serviceId BIGINT AUTO_INCREMENT PRIMARY KEY,
    serviceName VARCHAR(100) NOT NULL,
    serviceDesc TEXT NULL,
    serviceDuration INT NOT NULL,
    servicePrice DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS service_species (
    serviceId BIGINT NOT NULL,
    species VARCHAR(50) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (serviceId, species),
    CONSTRAINT fk_service_species_service FOREIGN KEY (serviceId) REFERENCES service(serviceId) ON DELETE CASCADE,
    INDEX idx_service_species_species (species)
);

CREATE TABLE IF NOT EXISTS product (
    prodId BIGINT AUTO_INCREMENT PRIMARY KEY,
    prodName VARCHAR(100) NOT NULL,
    prodPrice DECIMAL(10, 2) NOT NULL,
    categoryId BIGINT NOT NULL,
    prodDesc TEXT NULL,
    imageUrl VARCHAR(255) NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_product_category FOREIGN KEY (categoryId) REFERENCES category(categoryId)
);

CREATE TABLE IF NOT EXISTS inventory (
    inventoryId BIGINT AUTO_INCREMENT PRIMARY KEY,
    storeId BIGINT NOT NULL,
    prodId BIGINT NOT NULL,
    quantity INT NOT NULL DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT uq_inventory_store_product UNIQUE (storeId, prodId),
    CONSTRAINT fk_inventory_store FOREIGN KEY (storeId) REFERENCES storeLocation(storeId),
    CONSTRAINT fk_inventory_product FOREIGN KEY (prodId) REFERENCES product(prodId),
    INDEX idx_inventory_store (storeId),
    INDEX idx_inventory_product (prodId)
);

CREATE TABLE IF NOT EXISTS productSupplier (
    supId BIGINT NOT NULL,
    prodId BIGINT NOT NULL,
    cost DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (supId, prodId),
    CONSTRAINT fk_product_supplier_supplier FOREIGN KEY (supId) REFERENCES supplier(supId),
    CONSTRAINT fk_product_supplier_product FOREIGN KEY (prodId) REFERENCES product(prodId)
);

CREATE TABLE IF NOT EXISTS purchaseOrder (
    purchaseOrderId BIGINT AUTO_INCREMENT PRIMARY KEY,
    supId BIGINT NOT NULL,
    storeId BIGINT NOT NULL,
    orderDate DATE NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_purchase_order_supplier FOREIGN KEY (supId) REFERENCES supplier(supId),
    CONSTRAINT fk_purchase_order_store FOREIGN KEY (storeId) REFERENCES storeLocation(storeId),
    INDEX idx_purchase_order_store (storeId)
);

CREATE TABLE IF NOT EXISTS coupon (
    couponId BIGINT AUTO_INCREMENT PRIMARY KEY,
    couponCode VARCHAR(50) NOT NULL,
    discountType VARCHAR(20) NOT NULL,
    discountValue DECIMAL(10, 2) NOT NULL,
    minOrderAmount DECIMAL(10, 2) NULL,
    active BOOLEAN NOT NULL DEFAULT TRUE,
    startsAt DATETIME NULL,
    endsAt DATETIME NULL,
    usageLimit INT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT uq_coupon_code UNIQUE (couponCode)
);

CREATE TABLE IF NOT EXISTS pet (
    petId BIGINT AUTO_INCREMENT PRIMARY KEY,
    petName VARCHAR(50) NOT NULL,
    petSpecies VARCHAR(50) NOT NULL,
    petBreed VARCHAR(50) NULL,
    petAge INT NULL,
    petStatus VARCHAR(20) NOT NULL,
    petPrice DECIMAL(10, 2) NULL,
    imageUrl VARCHAR(255) NULL,
    ownerUserId BIGINT NULL,
    storeId BIGINT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_pet_owner_user FOREIGN KEY (ownerUserId) REFERENCES users(id) ON DELETE SET NULL,
    CONSTRAINT fk_pet_store FOREIGN KEY (storeId) REFERENCES storeLocation(storeId) ON DELETE SET NULL,
    INDEX idx_pet_owner_user (ownerUserId),
    INDEX idx_pet_store (storeId),
    INDEX idx_pet_species (petSpecies),
    INDEX idx_pet_name (petName)
);

CREATE TABLE IF NOT EXISTS appointment (
    appointmentId BIGINT AUTO_INCREMENT PRIMARY KEY,
    serviceId BIGINT NOT NULL,
    petId BIGINT NULL,
    customerId BIGINT NOT NULL,
    storeId BIGINT NOT NULL,
    employeeId BIGINT NOT NULL,
    appointmentDate DATE NOT NULL,
    appointmentTime TIME NOT NULL,
    appointmentStatus VARCHAR(20) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_appointment_service FOREIGN KEY (serviceId) REFERENCES service(serviceId),
    CONSTRAINT fk_appointment_pet FOREIGN KEY (petId) REFERENCES pet(petId) ON DELETE SET NULL,
    CONSTRAINT fk_appointment_customer FOREIGN KEY (customerId) REFERENCES users(id),
    CONSTRAINT fk_appointment_store FOREIGN KEY (storeId) REFERENCES storeLocation(storeId),
    CONSTRAINT fk_appointment_employee FOREIGN KEY (employeeId) REFERENCES users(id),
    INDEX idx_appointment_store (storeId),
    INDEX idx_appointment_employee (employeeId),
    INDEX idx_appointment_customer (customerId),
    INDEX idx_appointment_pet (petId),
    INDEX idx_appointment_date_status (appointmentDate, appointmentStatus)
);

CREATE TABLE IF NOT EXISTS adoption (
    adoptionId BIGINT AUTO_INCREMENT PRIMARY KEY,
    petId BIGINT NOT NULL,
    customerId BIGINT NOT NULL,
    employeeId BIGINT NOT NULL,
    sourceStoreId BIGINT NOT NULL,
    adoptionDate DATE NOT NULL,
    adoptionStatus VARCHAR(20) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_adoption_pet FOREIGN KEY (petId) REFERENCES pet(petId),
    CONSTRAINT fk_adoption_customer FOREIGN KEY (customerId) REFERENCES users(id),
    CONSTRAINT fk_adoption_employee FOREIGN KEY (employeeId) REFERENCES users(id),
    CONSTRAINT fk_adoption_source_store FOREIGN KEY (sourceStoreId) REFERENCES storeLocation(storeId),
    INDEX idx_adoption_store (sourceStoreId),
    INDEX idx_adoption_employee (employeeId)
);

CREATE TABLE IF NOT EXISTS cart (
    cartId BIGINT AUTO_INCREMENT PRIMARY KEY,
    userId BIGINT NOT NULL,
    storeId BIGINT NULL,
    couponId BIGINT NULL,
    cartStatus VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
    subtotalAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    discountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    totalAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    pointsApplied BOOLEAN NOT NULL DEFAULT FALSE,
    pointsDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    checkoutPending BOOLEAN NOT NULL DEFAULT FALSE,
    checkoutAmount DECIMAL(10, 2),
    checkoutStartedAt DATETIME,
    checkoutPaymentIntentId VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_cart_user FOREIGN KEY (userId) REFERENCES users(id),
    CONSTRAINT fk_cart_store FOREIGN KEY (storeId) REFERENCES storeLocation(storeId) ON DELETE SET NULL,
    CONSTRAINT fk_cart_coupon FOREIGN KEY (couponId) REFERENCES coupon(couponId) ON DELETE SET NULL,
    INDEX idx_cart_user (userId)
);

CREATE TABLE IF NOT EXISTS cart_item (
    cartItemId BIGINT AUTO_INCREMENT PRIMARY KEY,
    cartId BIGINT NOT NULL,
    prodId BIGINT NOT NULL,
    quantity INT NOT NULL,
    unitPrice DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_cart_item_cart FOREIGN KEY (cartId) REFERENCES cart(cartId) ON DELETE CASCADE,
    CONSTRAINT fk_cart_item_product FOREIGN KEY (prodId) REFERENCES product(prodId)
);

CREATE TABLE IF NOT EXISTS sale (
    saleId BIGINT AUTO_INCREMENT PRIMARY KEY,
    saleDate DATETIME NOT NULL,
    totalAmount DECIMAL(10, 2) NOT NULL,
    paymentMethod VARCHAR(50) NOT NULL,
    employeeId BIGINT NOT NULL,
    storeId BIGINT NOT NULL,
    customerId BIGINT NULL,
    isRefund BOOLEAN NOT NULL DEFAULT FALSE,
    originalSaleId BIGINT NULL,
    channel VARCHAR(20) NOT NULL DEFAULT 'In Store',
    cartId BIGINT NULL,
    couponId BIGINT NULL,
    subtotalAmount DECIMAL(10, 2) NULL,
    couponDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    employeeDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    pointsUsed INT NOT NULL DEFAULT 0,
    loyaltyDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    pointsEarned INT NOT NULL DEFAULT 0,
    pointsDiscountAmount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT uq_sale_cart_id UNIQUE (cartId),
    CONSTRAINT fk_sale_employee FOREIGN KEY (employeeId) REFERENCES users(id),
    CONSTRAINT fk_sale_store FOREIGN KEY (storeId) REFERENCES storeLocation(storeId),
    CONSTRAINT fk_sale_customer FOREIGN KEY (customerId) REFERENCES users(id) ON DELETE SET NULL,
    CONSTRAINT fk_sale_original_sale FOREIGN KEY (originalSaleId) REFERENCES sale(saleId),
    CONSTRAINT fk_sale_cart FOREIGN KEY (cartId) REFERENCES cart(cartId) ON DELETE SET NULL,
    CONSTRAINT fk_sale_coupon FOREIGN KEY (couponId) REFERENCES coupon(couponId) ON DELETE SET NULL,
    INDEX idx_sale_store (storeId),
    INDEX idx_sale_employee (employeeId),
    INDEX idx_sale_customer (customerId),
    INDEX idx_sale_date (saleDate)
);

CREATE TABLE IF NOT EXISTS saleItem (
    saleItemId BIGINT AUTO_INCREMENT PRIMARY KEY,
    saleId BIGINT NOT NULL,
    prodId BIGINT NOT NULL,
    quantity INT NOT NULL,
    unitPrice DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_sale_item_sale FOREIGN KEY (saleId) REFERENCES sale(saleId) ON DELETE CASCADE,
    CONSTRAINT fk_sale_item_product FOREIGN KEY (prodId) REFERENCES product(prodId)
);

CREATE TABLE IF NOT EXISTS refund (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    saleId BIGINT NOT NULL,
    customerId BIGINT NOT NULL,
    amount DECIMAL(10, 2) NOT NULL,
    reason VARCHAR(500) NOT NULL,
    status VARCHAR(20) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_refund_sale FOREIGN KEY (saleId) REFERENCES sale(saleId),
    CONSTRAINT fk_refund_customer FOREIGN KEY (customerId) REFERENCES users(id)
);

CREATE TABLE IF NOT EXISTS refund_item (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    refund_id BIGINT NOT NULL,
    prod_id BIGINT NOT NULL,
    quantity INT NOT NULL,
    unit_price DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_refund_item_refund FOREIGN KEY (refund_id) REFERENCES refund(id) ON DELETE CASCADE,
    CONSTRAINT fk_refund_item_product FOREIGN KEY (prod_id) REFERENCES product(prodId)
);

CREATE TABLE IF NOT EXISTS passwordResetToken (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    userId BIGINT NOT NULL,
    tokenHash VARCHAR(64) NOT NULL,
    expiresAt DATETIME NOT NULL,
    usedAt DATETIME NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT uq_password_reset_token_hash UNIQUE (tokenHash),
    CONSTRAINT fk_password_reset_token_user FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE,
    INDEX idx_password_reset_token_user (userId),
    INDEX idx_password_reset_token_expires (expiresAt)
);

CREATE TABLE IF NOT EXISTS conversation (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    customerId BIGINT NOT NULL,
    staffId BIGINT NULL,
    status VARCHAR(20) NOT NULL DEFAULT 'OPEN',
    mode VARCHAR(20) NOT NULL DEFAULT 'AUTOMATED',
    humanRequestedAt TIMESTAMP NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    CONSTRAINT fk_conversation_customer FOREIGN KEY (customerId) REFERENCES users(id),
    CONSTRAINT fk_conversation_staff FOREIGN KEY (staffId) REFERENCES users(id) ON DELETE SET NULL,
    INDEX idx_conversation_customer (customerId),
    INDEX idx_conversation_staff (staffId)
);

CREATE TABLE IF NOT EXISTS message (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    conversationId BIGINT NOT NULL,
    senderId BIGINT NOT NULL,
    content TEXT NULL,
    attachmentUrl VARCHAR(255) NULL,
    attachmentName VARCHAR(255) NULL,
    attachmentMimeType VARCHAR(100) NULL,
    attachmentSizeBytes BIGINT NULL,
    timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    isRead BOOLEAN NOT NULL DEFAULT FALSE,
    CONSTRAINT fk_message_conversation FOREIGN KEY (conversationId) REFERENCES conversation(id) ON DELETE CASCADE,
    CONSTRAINT fk_message_sender FOREIGN KEY (senderId) REFERENCES users(id)
);

CREATE TABLE IF NOT EXISTS activityLog (
    logId BIGINT AUTO_INCREMENT PRIMARY KEY,
    userId BIGINT NOT NULL,
    storeId BIGINT NULL,
    usernameSnapshot VARCHAR(50) NULL,
    fullNameSnapshot VARCHAR(100) NULL,
    roleSnapshot VARCHAR(20) NULL,
    storeNameSnapshot VARCHAR(100) NULL,
    activity TEXT NOT NULL,
    logTimestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_activity_log_user FOREIGN KEY (userId) REFERENCES users(id),
    CONSTRAINT fk_activity_log_store FOREIGN KEY (storeId) REFERENCES storeLocation(storeId) ON DELETE SET NULL,
    INDEX idx_activity_log_store (storeId),
    INDEX idx_activity_log_timestamp_id (logTimestamp, logId)
);

