#!/bin/bash
#
# Create Restricted Database User - Safe Script
#
# This script creates a database user with restricted permissions to enforce
# transaction immutability. The user can:
# - SELECT and INSERT on all tables
# - UPDATE and DELETE on all tables EXCEPT transactions and transaction_types
#
# This enforces financial transaction immutability at the database level.
#
# Usage:
#   ./scripts/create-restricted-db-user-safe.sh [username] [password]
#
# If username/password not provided, will prompt interactively.

set -e  # Exit on error

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Create Restricted Database User${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""

# Load database name from .env
if [ ! -f .env ]; then
    echo -e "${RED}Error: .env file not found${NC}"
    exit 1
fi

DB_DATABASE=$(grep "^DB_DATABASE=" .env | cut -d '=' -f2 | sed 's/#.*//' | tr -d '"' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/\r$//')
DB_HOST=$(grep "^DB_HOST=" .env | cut -d '=' -f2 | sed 's/#.*//' | tr -d '"' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/\r$//')

# Default to localhost if not set
if [ -z "$DB_HOST" ]; then
    DB_HOST="localhost"
fi

echo -e "${BLUE}Database:${NC} $DB_DATABASE"
echo -e "${BLUE}Host:${NC} $DB_HOST"
echo ""

# Determine authentication method
USE_SUDO=false
ROOT_USER="root"
ROOT_PASSWORD=""

# If running as root, try socket authentication first
if [ "$EUID" -eq 0 ]; then
    echo -e "${YELLOW}Running as root user, testing socket authentication...${NC}"
    if mysql -e "SELECT 1;" &> /dev/null; then
        echo -e "${GREEN}✓ Socket authentication successful${NC}"
        USE_SUDO=true
    else
        echo -e "${YELLOW}Socket authentication failed, falling back to credential-based auth${NC}"
    fi
fi

# If not using socket auth, get credentials
if [ "$USE_SUDO" = false ]; then
    echo ""
    echo -e "${YELLOW}Please provide MySQL root credentials to create the restricted user:${NC}"
    read -p "Root username (default: root): " ROOT_USER_INPUT
    ROOT_USER=${ROOT_USER_INPUT:-root}

    read -s -p "Root password: " ROOT_PASSWORD
    echo ""

    # Test root connection
    echo -e "${YELLOW}Testing database connection...${NC}"
    if ! MYSQL_PWD="$ROOT_PASSWORD" mysql -h"$DB_HOST" -u"$ROOT_USER" -e "SELECT 1;" 2>/dev/null; then
        echo -e "${RED}Error: Cannot connect to database with provided credentials${NC}"
        echo ""
        echo -e "${YELLOW}Troubleshooting:${NC}"
        echo -e "  1. Check your MySQL root password"
        echo -e "  2. Verify MySQL is running: ${BLUE}systemctl status mysql${NC}"
        echo -e "  3. Check MySQL is listening on ${DB_HOST}: ${BLUE}netstat -tlnp | grep mysql${NC}"
        echo -e "  4. Verify user '${ROOT_USER}' can connect from '${DB_HOST}'"
        echo ""
        echo -e "${YELLOW}Debug: Attempting to connect as:${NC}"
        echo -e "  User: ${ROOT_USER}"
        echo -e "  Host: ${DB_HOST}"
        exit 1
    fi
    echo -e "${GREEN}✓ Database connection successful${NC}"
fi

echo ""

# Check if user has CREATE USER privilege
echo -e "${YELLOW}Checking for CREATE USER privilege...${NC}"
if [ "$USE_SUDO" = true ]; then
    HAS_CREATE_USER=$(mysql -N -e "SELECT COUNT(*) FROM information_schema.user_privileges WHERE PRIVILEGE_TYPE='CREATE USER' AND GRANTEE LIKE '%root%';" 2>/dev/null || echo "0")
else
    HAS_CREATE_USER=$(MYSQL_PWD="$ROOT_PASSWORD" mysql -h"$DB_HOST" -u"$ROOT_USER" -N -e "SELECT COUNT(*) FROM information_schema.user_privileges WHERE PRIVILEGE_TYPE='CREATE USER' AND GRANTEE LIKE '%${ROOT_USER}%';" 2>/dev/null || echo "0")
fi

if [ "$HAS_CREATE_USER" = "0" ]; then
    echo -e "${RED}Error: User '${ROOT_USER}' does not have CREATE USER privilege${NC}"
    echo ""
    echo -e "${YELLOW}Solutions:${NC}"
    echo ""
    echo -e "  ${BLUE}Option 1: Use sudo mysql (recommended for servers)${NC}"
    echo -e "  If your server uses socket authentication for root, run:"
    echo -e "  ${GREEN}sudo ./scripts/create-restricted-db-user-safe.sh${NC}"
    echo ""
    echo -e "  ${BLUE}Option 2: Grant CREATE USER privilege${NC}"
    echo -e "  Connect as a user with GRANT privilege and run:"
    echo -e "  ${GREEN}GRANT CREATE USER ON *.* TO '${ROOT_USER}'@'${DB_HOST}';${NC}"
    echo -e "  ${GREEN}FLUSH PRIVILEGES;${NC}"
    echo ""
    echo -e "  ${BLUE}Option 3: Use MySQL root user${NC}"
    echo -e "  On Ubuntu/Debian servers, try running without password:"
    echo -e "  ${GREEN}sudo mysql -u root${NC}"
    echo -e "  Then manually run the SQL commands from:"
    echo -e "  ${GREEN}scripts/create-restricted-db-user.sql${NC}"
    echo ""
    exit 1
fi
echo -e "${GREEN}✓ CREATE USER privilege confirmed${NC}"
echo ""

# Get new user details
if [ -z "$1" ]; then
    read -p "Enter new restricted username (default: ${DB_DATABASE}_dev): " NEW_USER
    NEW_USER=${NEW_USER:-${DB_DATABASE}_dev}
else
    NEW_USER="$1"
fi

if [ -z "$2" ]; then
    echo -e "${YELLOW}Generate strong password for ${NEW_USER}? (y/n)${NC}"
    read -p "> " GENERATE_PASSWORD

    if [[ "$GENERATE_PASSWORD" =~ ^[Yy]$ ]]; then
        # Generate strong random password
        NEW_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-32)
        echo -e "${GREEN}Generated password: ${NEW_PASSWORD}${NC}"
    else
        read -s -p "Enter password for ${NEW_USER}: " NEW_PASSWORD
        echo ""
        read -s -p "Confirm password: " NEW_PASSWORD_CONFIRM
        echo ""

        if [ "$NEW_PASSWORD" != "$NEW_PASSWORD_CONFIRM" ]; then
            echo -e "${RED}Error: Passwords do not match${NC}"
            exit 1
        fi
    fi
else
    NEW_PASSWORD="$2"
fi

echo ""
echo -e "${BLUE}Creating user:${NC} ${NEW_USER}@${DB_HOST}"
echo -e "${BLUE}For database:${NC} ${DB_DATABASE}"
echo ""

# Check if user already exists
if [ "$USE_SUDO" = true ]; then
    USER_EXISTS=$(mysql -N -e "SELECT COUNT(*) FROM mysql.user WHERE user='$NEW_USER' AND host='$DB_HOST';" 2>/dev/null || echo "0")
else
    USER_EXISTS=$(MYSQL_PWD="$ROOT_PASSWORD" mysql -h"$DB_HOST" -u"$ROOT_USER" -N -e "SELECT COUNT(*) FROM mysql.user WHERE user='$NEW_USER' AND host='$DB_HOST';" 2>/dev/null || echo "0")
fi

if [ "$USER_EXISTS" != "0" ]; then
    echo -e "${YELLOW}Warning: User '${NEW_USER}'@'${DB_HOST}' already exists${NC}"
    read -p "Drop and recreate user? (y/n): " RECREATE

    if [[ "$RECREATE" =~ ^[Yy]$ ]]; then
        echo -e "${YELLOW}Dropping existing user...${NC}"
        if [ "$USE_SUDO" = true ]; then
            mysql <<EOF
DROP USER IF EXISTS '${NEW_USER}'@'${DB_HOST}';
DROP USER IF EXISTS '${NEW_USER}'@'localhost';
DROP USER IF EXISTS '${NEW_USER}'@'127.0.0.1';
FLUSH PRIVILEGES;
EOF
        else
            MYSQL_PWD="$ROOT_PASSWORD" mysql -h"$DB_HOST" -u"$ROOT_USER" <<EOF
DROP USER IF EXISTS '${NEW_USER}'@'${DB_HOST}';
DROP USER IF EXISTS '${NEW_USER}'@'localhost';
DROP USER IF EXISTS '${NEW_USER}'@'127.0.0.1';
FLUSH PRIVILEGES;
EOF
        fi
        echo -e "${GREEN}✓ Existing user dropped${NC}"
    else
        echo "Exiting without changes"
        exit 0
    fi
fi

echo ""
echo -e "${YELLOW}Creating restricted database user...${NC}"
echo ""

# Get all tables
if [ "$USE_SUDO" = true ]; then
    ALL_TABLES=$(mysql -N -e "SHOW TABLES FROM ${DB_DATABASE};" | tr '\n' ' ')
else
    ALL_TABLES=$(MYSQL_PWD="$ROOT_PASSWORD" mysql -h"$DB_HOST" -u"$ROOT_USER" -N -e "SHOW TABLES FROM ${DB_DATABASE};" | tr '\n' ' ')
fi

# Count tables
TABLE_COUNT=$(echo "$ALL_TABLES" | wc -w)

# Immutable tables (cannot UPDATE or DELETE)
IMMUTABLE_TABLES="transactions transaction_types"

# Count immutable tables
IMMUTABLE_COUNT=$(echo "$IMMUTABLE_TABLES" | wc -w)

# Calculate mutable tables count
MUTABLE_COUNT=$((TABLE_COUNT - IMMUTABLE_COUNT))

echo -e "${BLUE}Total tables:${NC} $TABLE_COUNT"
echo -e "${BLUE}Immutable tables:${NC} $IMMUTABLE_COUNT (transactions, transaction_types)"
echo -e "${BLUE}Mutable tables:${NC} $MUTABLE_COUNT"
echo ""

# Create SQL script
SQL_SCRIPT=$(cat <<EOF
-- Create restricted database user for ${DB_DATABASE}
-- This user enforces transaction immutability at the database level

-- Create user for all common connection types
CREATE USER IF NOT EXISTS '${NEW_USER}'@'${DB_HOST}' IDENTIFIED BY '${NEW_PASSWORD}';
CREATE USER IF NOT EXISTS '${NEW_USER}'@'localhost' IDENTIFIED BY '${NEW_PASSWORD}';
CREATE USER IF NOT EXISTS '${NEW_USER}'@'127.0.0.1' IDENTIFIED BY '${NEW_PASSWORD}';

-- Grant SELECT and INSERT on all tables (basic read/write access)
GRANT SELECT, INSERT ON ${DB_DATABASE}.* TO '${NEW_USER}'@'${DB_HOST}';
GRANT SELECT, INSERT ON ${DB_DATABASE}.* TO '${NEW_USER}'@'localhost';
GRANT SELECT, INSERT ON ${DB_DATABASE}.* TO '${NEW_USER}'@'127.0.0.1';

-- Grant UPDATE and DELETE on each mutable table
EOF
)

# Add UPDATE/DELETE grants for each table except immutable ones
for table in $ALL_TABLES; do
    # Skip immutable tables
    if [[ " $IMMUTABLE_TABLES " =~ " $table " ]]; then
        continue
    fi

    SQL_SCRIPT+=$(cat <<EOF

GRANT UPDATE, DELETE ON ${DB_DATABASE}.${table} TO '${NEW_USER}'@'${DB_HOST}';
GRANT UPDATE, DELETE ON ${DB_DATABASE}.${table} TO '${NEW_USER}'@'localhost';
GRANT UPDATE, DELETE ON ${DB_DATABASE}.${table} TO '${NEW_USER}'@'127.0.0.1';
EOF
)
done

SQL_SCRIPT+=$(cat <<EOF


-- Apply permission changes
FLUSH PRIVILEGES;

-- Display created user
SELECT
    'User created successfully' as status,
    '${NEW_USER}' as username,
    GROUP_CONCAT(DISTINCT host) as hosts
FROM mysql.user
WHERE user = '${NEW_USER}';
EOF
)

# Execute SQL script
echo -e "${YELLOW}Executing SQL commands...${NC}"
if [ "$USE_SUDO" = true ]; then
    echo "$SQL_SCRIPT" | mysql
else
    echo "$SQL_SCRIPT" | MYSQL_PWD="$ROOT_PASSWORD" mysql -h"$DB_HOST" -u"$ROOT_USER"
fi

if [ $? -eq 0 ]; then
    echo ""
    echo -e "${GREEN}========================================${NC}"
    echo -e "${GREEN}✓ User created successfully!${NC}"
    echo -e "${GREEN}========================================${NC}"
    echo ""
    echo -e "${BLUE}User Details:${NC}"
    echo -e "  Username: ${GREEN}${NEW_USER}${NC}"
    echo -e "  Password: ${GREEN}${NEW_PASSWORD}${NC}"
    echo -e "  Database: ${GREEN}${DB_DATABASE}${NC}"
    echo -e "  Hosts: ${GREEN}${DB_HOST}, localhost, 127.0.0.1${NC}"
    echo ""
    echo -e "${BLUE}Permissions:${NC}"
    echo -e "  ${GREEN}✓${NC} SELECT, INSERT on ${TABLE_COUNT} tables"
    echo -e "  ${GREEN}✓${NC} UPDATE, DELETE on ${MUTABLE_COUNT} mutable tables"
    echo -e "  ${RED}✗${NC} UPDATE, DELETE on ${IMMUTABLE_COUNT} immutable tables (transactions, transaction_types)"
    echo ""
    echo -e "${YELLOW}Next Steps:${NC}"
    echo ""
    echo -e "1. ${BLUE}Backup your current .env file:${NC}"
    echo -e "   cp .env .env.backup-\$(date +'%Y%m%d-%H%M%S')"
    echo ""
    echo -e "2. ${BLUE}Update your .env file:${NC}"
    echo -e "   DB_USERNAME=${NEW_USER}"
    echo -e "   DB_PASSWORD=${NEW_PASSWORD}"
    echo ""
    echo -e "3. ${BLUE}Clear Laravel configuration cache:${NC}"
    echo -e "   php artisan config:clear"
    echo ""
    echo -e "4. ${BLUE}Test the connection:${NC}"
    echo -e "   php artisan tinker --execute=\"DB::connection()->getPdo();\""
    echo ""
    echo -e "5. ${BLUE}Verify transaction immutability:${NC}"
    echo -e "   ./scripts/test-transaction-immutability.sh"
    echo ""
    echo -e "${YELLOW}IMPORTANT:${NC}"
    echo -e "  • For database migrations, use root credentials:"
    echo -e "    DB_USERNAME=root php artisan migrate"
    echo -e "  • Keep root credentials secure and separate"
    echo -e "  • Save the new user credentials securely"
    echo ""

    # Save credentials to a secure file
    CREDENTIALS_FILE=".credentials-${NEW_USER}"
    cat > "$CREDENTIALS_FILE" <<EOC
# Database credentials for ${NEW_USER}
# Created: $(date)
# Database: ${DB_DATABASE}

DB_USERNAME=${NEW_USER}
DB_PASSWORD=${NEW_PASSWORD}
EOC

    chmod 600 "$CREDENTIALS_FILE"
    echo -e "${GREEN}✓ Credentials saved to: ${CREDENTIALS_FILE}${NC}"
    echo -e "${YELLOW}  (This file has been created with restricted permissions: 600)${NC}"
    echo ""
else
    echo ""
    echo -e "${RED}========================================${NC}"
    echo -e "${RED}✗ Error creating user${NC}"
    echo -e "${RED}========================================${NC}"
    echo ""
    exit 1
fi
