#!/bin/bash

# URL Shortener Complete Installation Script
# Simpan sebagai: install-url-shortener.sh

set -e

echo "========================================="
echo "   URL SHORTENER COMPLETE INSTALLATION"
echo "   Domain: id.polasaja.com"
echo "========================================="
echo ""

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

print_success() { echo -e "${GREEN}✓ $1${NC}"; }
print_error() { echo -e "${RED}✗ $1${NC}"; }
print_info() { echo -e "${YELLOW}➜ $1${NC}"; }
print_header() { echo -e "${BLUE}=== $1 ===${NC}"; }

# Create main directory if not exists
if [ ! -d "url-shortener" ]; then
    mkdir -p url-shortener
fi
cd url-shortener

print_header "Creating directory structure"

# Create all directories
mkdir -p app/{Controllers,Models,Services,Repositories/{Contracts},DTO,Middleware,Validators,Exceptions,Helpers}
mkdir -p config
mkdir -p database/{migrations,seeders,factories}
mkdir -p public/{assets/{css,js,images},uploads}
mkdir -p resources/{views/{layouts,urls,auth,errors},lang/{en,id},assets/{scss,js}}
mkdir -p routes
mkdir -p bootstrap
mkdir -p storage/{cache/{views,data},logs,sessions,temp}
mkdir -p tests/{Unit,Feature}

print_success "Directory structure created"

# Create .env file
cat > .env << 'EOF'
APP_NAME="PolaSaja URL Shortener"
APP_URL=http://id.polasaja.com
APP_ENV=production
APP_DEBUG=false
APP_TIMEZONE=Asia/Jakarta

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=url_shortener
DB_USERNAME=root
DB_PASSWORD=

CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120

SHORT_CODE_LENGTH=6
SHORT_CODE_CHARS=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=60

ADMIN_EMAIL=admin@id.polasaja.com
EOF

cat > .env.example << 'EOF'
APP_NAME="URL Shortener"
APP_URL=http://localhost:8000
APP_ENV=local
APP_DEBUG=true
APP_TIMEZONE=UTC

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=url_shortener
DB_USERNAME=root
DB_PASSWORD=

CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120

SHORT_CODE_LENGTH=6
SHORT_CODE_CHARS=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=60

ADMIN_EMAIL=admin@example.com
EOF

print_success "Environment files created"

# Create composer.json
cat > composer.json << 'EOF'
{
    "name": "polasaja/url-shortener",
    "description": "Professional URL Shortener for id.polasaja.com",
    "type": "project",
    "require": {
        "php": ">=7.4.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    },
    "config": {
        "optimize-autoloader": true
    }
}
EOF

print_success "composer.json created"

# Create .gitignore
cat > .gitignore << 'EOF'
/vendor/
.env
/storage/*.sqlite
/storage/logs/*.log
/storage/cache/*
/storage/sessions/*
/public/uploads/*
composer.lock
.DS_Store
.idea/
.vscode/
*.log
*.sql
EOF

print_success ".gitignore created"

# ============================================
# CONFIG FILES
# ============================================
print_header "Creating configuration files"

cat > config/app.php << 'EOF'
<?php

return [
    'name' => getenv('APP_NAME') ?: 'URL Shortener',
    'version' => '1.0.0',
    'debug' => getenv('APP_DEBUG') === 'true',
    'timezone' => getenv('APP_TIMEZONE') ?: 'UTC',
    'url' => getenv('APP_URL') ?: 'http://localhost',
    
    'short_code' => [
        'length' => (int)(getenv('SHORT_CODE_LENGTH') ?: 6),
        'chars' => getenv('SHORT_CODE_CHARS') ?: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
    ],
    
    'rate_limit' => [
        'enabled' => getenv('RATE_LIMIT_ENABLED') === 'true',
        'per_minute' => (int)(getenv('RATE_LIMIT_PER_MINUTE') ?: 60),
    ],
];
EOF

cat > config/database.php << 'EOF'
<?php

return [
    'default' => getenv('DB_CONNECTION') ?: 'mysql',
    
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'host' => getenv('DB_HOST') ?: 'localhost',
            'port' => getenv('DB_PORT') ?: '3306',
            'database' => getenv('DB_DATABASE') ?: 'url_shortener',
            'username' => getenv('DB_USERNAME') ?: 'root',
            'password' => getenv('DB_PASSWORD') ?: '',
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
        ],
    ],
];
EOF

cat > config/cache.php << 'EOF'
<?php

return [
    'default' => getenv('CACHE_DRIVER') ?: 'file',
    
    'stores' => [
        'file' => [
            'driver' => 'file',
            'path' => __DIR__ . '/../storage/cache/data',
        ],
    ],
    
    'prefix' => 'url_shortener_',
];
EOF

cat > config/constants.php << 'EOF'
<?php

// HTTP Status Codes
define('HTTP_OK', 200);
define('HTTP_CREATED', 201);
define('HTTP_BAD_REQUEST', 400);
define('HTTP_UNAUTHORIZED', 401);
define('HTTP_FORBIDDEN', 403);
define('HTTP_NOT_FOUND', 404);
define('HTTP_METHOD_NOT_ALLOWED', 405);
define('HTTP_TOO_MANY_REQUESTS', 429);
define('HTTP_INTERNAL_SERVER_ERROR', 500);

// User Roles
define('ROLE_USER', 'user');
define('ROLE_ADMIN', 'admin');

// Link Status
define('LINK_ACTIVE', 1);
define('LINK_INACTIVE', 0);
define('LINK_EXPIRED', 2);

// Session Keys
define('SESSION_USER_ID', 'user_id');
define('SESSION_USER_EMAIL', 'user_email');
define('SESSION_USER_NAME', 'user_name');
define('SESSION_USER_ROLE', 'user_role');

// Cache Keys
define('CACHE_LINK_PREFIX', 'link_');
define('CACHE_STATS_PREFIX', 'stats_');
EOF

print_success "Configuration files created"

# ============================================
# DATABASE MIGRATIONS
# ============================================
print_header "Creating database migrations"

cat > database/migrations/2024_01_01_000001_create_urls_table.php << 'EOF'
<?php

return [
    'up' => "
        CREATE TABLE IF NOT EXISTS `links` (
            `id` int(11) NOT NULL AUTO_INCREMENT,
            `title` varchar(255) DEFAULT NULL,
            `short_code` varchar(50) NOT NULL,
            `original_url` text NOT NULL,
            `original_domain` varchar(255) DEFAULT NULL,
            `user_id` int(11) DEFAULT NULL,
            `clicks` int(11) DEFAULT '0',
            `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
            `expires_at` datetime DEFAULT NULL,
            `is_active` tinyint(1) DEFAULT '1',
            `last_edited_at` datetime DEFAULT NULL,
            `last_edited_ip` varchar(45) DEFAULT NULL,
            `display_order` int(11) DEFAULT '0',
            `link_order` int(11) DEFAULT '0',
            `created_ip` varchar(45) DEFAULT NULL,
            `last_edited_by` varchar(100) DEFAULT NULL,
            PRIMARY KEY (`id`),
            UNIQUE KEY `short_code` (`short_code`),
            KEY `user_id_idx` (`user_id`),
            KEY `short_code_idx` (`short_code`),
            KEY `is_active_idx` (`is_active`),
            KEY `expires_at_idx` (`expires_at`),
            KEY `clicks_idx` (`clicks`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
    ",
    'down' => "DROP TABLE IF EXISTS `links`"
];
EOF

cat > database/migrations/2024_01_01_000002_create_users_table.php << 'EOF'
<?php

return [
    'up' => "
        CREATE TABLE IF NOT EXISTS `users` (
            `id` int(11) NOT NULL AUTO_INCREMENT,
            `name` varchar(100) NOT NULL,
            `email` varchar(255) NOT NULL,
            `password` varchar(255) NOT NULL,
            `role` enum('user','admin') DEFAULT 'user',
            `api_key` varchar(64) DEFAULT NULL,
            `email_verified` tinyint(1) DEFAULT '0',
            `verification_token` varchar(64) DEFAULT NULL,
            `reset_token` varchar(64) DEFAULT NULL,
            `reset_token_expires` datetime DEFAULT NULL,
            `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
            `updated_at` timestamp NULL DEFAULT NULL,
            `last_login_at` datetime DEFAULT NULL,
            `last_login_ip` varchar(45) DEFAULT NULL,
            `is_active` tinyint(1) DEFAULT '1',
            PRIMARY KEY (`id`),
            UNIQUE KEY `email` (`email`),
            UNIQUE KEY `api_key` (`api_key`),
            KEY `email_verified_idx` (`email_verified`),
            KEY `is_active_idx` (`is_active`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
    ",
    'down' => "DROP TABLE IF EXISTS `users`"
];
EOF

cat > database/migrations/2024_01_01_000003_create_clicks_table.php << 'EOF'
<?php

return [
    'up' => "
        CREATE TABLE IF NOT EXISTS `clicks` (
            `id` int(11) NOT NULL AUTO_INCREMENT,
            `link_id` int(11) NOT NULL,
            `ip_address` varchar(45) DEFAULT NULL,
            `user_agent` text,
            `referer` text,
            `country` varchar(2) DEFAULT NULL,
            `city` varchar(100) DEFAULT NULL,
            `device_type` enum('desktop','mobile','tablet','bot') DEFAULT NULL,
            `browser` varchar(50) DEFAULT NULL,
            `os` varchar(50) DEFAULT NULL,
            `clicked_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (`id`),
            KEY `link_id_idx` (`link_id`),
            KEY `clicked_at_idx` (`clicked_at`),
            KEY `country_idx` (`country`),
            KEY `device_type_idx` (`device_type`),
            FOREIGN KEY (`link_id`) REFERENCES `links`(`id`) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
    ",
    'down' => "DROP TABLE IF EXISTS `clicks`"
];
EOF

print_success "Database migrations created"

# ============================================
# DTO FILES
# ============================================
print_header "Creating DTO files"

cat > app/DTO/CreateUrlDTO.php << 'EOF'
<?php

namespace App\DTO;

class CreateUrlDTO
{
    public $title;
    public $originalUrl;
    public $userId;
    public $customShortCode;
    public $expiresAt;
    public $createdIp;
    
    public function __construct(array $data)
    {
        $this->title = $data['title'] ?? null;
        $this->originalUrl = $data['original_url'] ?? '';
        $this->userId = $data['user_id'] ?? null;
        $this->customShortCode = $data['custom_short_code'] ?? null;
        $this->expiresAt = $data['expires_at'] ?? null;
        $this->createdIp = $data['created_ip'] ?? $_SERVER['REMOTE_ADDR'] ?? null;
    }
    
    public function validate()
    {
        if (!filter_var($this->originalUrl, FILTER_VALIDATE_URL)) {
            throw new \InvalidArgumentException('Invalid URL format');
        }
        
        if ($this->customShortCode && !preg_match('/^[a-zA-Z0-9]+$/', $this->customShortCode)) {
            throw new \InvalidArgumentException('Custom short code can only contain letters and numbers');
        }
        
        return true;
    }
    
    public function toArray()
    {
        return [
            'title' => $this->title,
            'original_url' => $this->originalUrl,
            'user_id' => $this->userId,
            'custom_short_code' => $this->customShortCode,
            'expires_at' => $this->expiresAt,
            'created_ip' => $this->createdIp,
        ];
    }
}
EOF

cat > app/DTO/UrlResponseDTO.php << 'EOF'
<?php

namespace App\DTO;

class UrlResponseDTO
{
    public $id;
    public $title;
    public $shortCode;
    public $shortUrl;
    public $originalUrl;
    public $clicks;
    public $createdAt;
    public $expiresAt;
    public $isActive;
    public $qrCode;
    
    public function __construct(array $data, $baseUrl)
    {
        $this->id = $data['id'];
        $this->title = $data['title'] ?? null;
        $this->shortCode = $data['short_code'];
        $this->shortUrl = rtrim($baseUrl, '/') . '/' . $data['short_code'];
        $this->originalUrl = $data['original_url'];
        $this->clicks = (int)($data['clicks'] ?? 0);
        $this->createdAt = $data['created_at'];
        $this->expiresAt = $data['expires_at'] ?? null;
        $this->isActive = ($data['is_active'] ?? 1) == 1;
        $this->qrCode = $this->shortUrl . '.qr';
    }
    
    public function toArray()
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'short_code' => $this->shortCode,
            'short_url' => $this->shortUrl,
            'original_url' => $this->originalUrl,
            'clicks' => $this->clicks,
            'created_at' => $this->createdAt,
            'expires_at' => $this->expiresAt,
            'is_active' => $this->isActive,
            'qr_code' => $this->qrCode,
        ];
    }
    
    public function toJson()
    {
        return json_encode($this->toArray());
    }
}
EOF

print_success "DTO files created"

# ============================================
# MODEL FILES
# ============================================
print_header "Creating Model files"

cat > app/Models/Url.php << 'EOF'
<?php

namespace App\Models;

class Url
{
    public $id;
    public $title;
    public $shortCode;
    public $originalUrl;
    public $originalDomain;
    public $userId;
    public $clicks;
    public $createdAt;
    public $expiresAt;
    public $isActive;
    public $lastEditedAt;
    public $lastEditedIp;
    public $displayOrder;
    public $linkOrder;
    public $createdIp;
    public $lastEditedBy;
    
    public function __construct(array $data = [])
    {
        $this->hydrate($data);
    }
    
    public function hydrate(array $data)
    {
        $this->id = $data['id'] ?? null;
        $this->title = $data['title'] ?? null;
        $this->shortCode = $data['short_code'] ?? null;
        $this->originalUrl = $data['original_url'] ?? null;
        $this->originalDomain = $data['original_domain'] ?? null;
        $this->userId = $data['user_id'] ?? null;
        $this->clicks = (int)($data['clicks'] ?? 0);
        $this->createdAt = $data['created_at'] ?? null;
        $this->expiresAt = $data['expires_at'] ?? null;
        $this->isActive = (int)($data['is_active'] ?? 1);
        $this->lastEditedAt = $data['last_edited_at'] ?? null;
        $this->lastEditedIp = $data['last_edited_ip'] ?? null;
        $this->displayOrder = (int)($data['display_order'] ?? 0);
        $this->linkOrder = (int)($data['link_order'] ?? 0);
        $this->createdIp = $data['created_ip'] ?? null;
        $this->lastEditedBy = $data['last_edited_by'] ?? null;
    }
    
    public function isExpired()
    {
        if (!$this->expiresAt) {
            return false;
        }
        return strtotime($this->expiresAt) < time();
    }
    
    public function canAccess()
    {
        return $this->isActive == 1 && !$this->isExpired();
    }
    
    public function incrementClicks()
    {
        $this->clicks++;
    }
    
    public function toArray()
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'short_code' => $this->shortCode,
            'original_url' => $this->originalUrl,
            'original_domain' => $this->originalDomain,
            'user_id' => $this->userId,
            'clicks' => $this->clicks,
            'created_at' => $this->createdAt,
            'expires_at' => $this->expiresAt,
            'is_active' => $this->isActive,
        ];
    }
}
EOF

cat > app/Models/User.php << 'EOF'
<?php

namespace App\Models;

class User
{
    public $id;
    public $name;
    public $email;
    public $password;
    public $role;
    public $apiKey;
    public $emailVerified;
    public $createdAt;
    public $lastLoginAt;
    public $lastLoginIp;
    public $isActive;
    
    public function __construct(array $data = [])
    {
        $this->hydrate($data);
    }
    
    public function hydrate(array $data)
    {
        $this->id = $data['id'] ?? null;
        $this->name = $data['name'] ?? null;
        $this->email = $data['email'] ?? null;
        $this->password = $data['password'] ?? null;
        $this->role = $data['role'] ?? 'user';
        $this->apiKey = $data['api_key'] ?? null;
        $this->emailVerified = (int)($data['email_verified'] ?? 0);
        $this->createdAt = $data['created_at'] ?? null;
        $this->lastLoginAt = $data['last_login_at'] ?? null;
        $this->lastLoginIp = $data['last_login_ip'] ?? null;
        $this->isActive = (int)($data['is_active'] ?? 1);
    }
    
    public function isAdmin()
    {
        return $this->role === 'admin';
    }
    
    public function isVerified()
    {
        return $this->emailVerified == 1;
    }
    
    public function toArray()
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'role' => $this->role,
            'email_verified' => $this->emailVerified,
            'created_at' => $this->createdAt,
            'is_active' => $this->isActive,
        ];
    }
}
EOF

cat > app/Models/Click.php << 'EOF'
<?php

namespace App\Models;

class Click
{
    public $id;
    public $linkId;
    public $ipAddress;
    public $userAgent;
    public $referer;
    public $country;
    public $city;
    public $deviceType;
    public $browser;
    public $os;
    public $clickedAt;
    
    public function __construct(array $data = [])
    {
        $this->hydrate($data);
    }
    
    public function hydrate(array $data)
    {
        $this->id = $data['id'] ?? null;
        $this->linkId = $data['link_id'] ?? null;
        $this->ipAddress = $data['ip_address'] ?? null;
        $this->userAgent = $data['user_agent'] ?? null;
        $this->referer = $data['referer'] ?? null;
        $this->country = $data['country'] ?? null;
        $this->city = $data['city'] ?? null;
        $this->deviceType = $data['device_type'] ?? null;
        $this->browser = $data['browser'] ?? null;
        $this->os = $data['os'] ?? null;
        $this->clickedAt = $data['clicked_at'] ?? null;
    }
    
    public function detectDevice()
    {
        $ua = strtolower($this->userAgent ?? '');
        
        if (strpos($ua, 'mobile') !== false) {
            return 'mobile';
        } elseif (strpos($ua, 'tablet') !== false) {
            return 'tablet';
        } elseif (strpos($ua, 'bot') !== false || strpos($ua, 'crawl') !== false) {
            return 'bot';
        }
        return 'desktop';
    }
    
    public function detectBrowser()
    {
        $ua = $this->userAgent ?? '';
        
        if (strpos($ua, 'Chrome') !== false) return 'Chrome';
        if (strpos($ua, 'Firefox') !== false) return 'Firefox';
        if (strpos($ua, 'Safari') !== false) return 'Safari';
        if (strpos($ua, 'Edge') !== false) return 'Edge';
        if (strpos($ua, 'Opera') !== false) return 'Opera';
        if (strpos($ua, 'MSIE') !== false || strpos($ua, 'Trident') !== false) return 'Internet Explorer';
        
        return 'Unknown';
    }
    
    public function detectOS()
    {
        $ua = $this->userAgent ?? '';
        
        if (strpos($ua, 'Windows') !== false) return 'Windows';
        if (strpos($ua, 'Mac') !== false) return 'macOS';
        if (strpos($ua, 'Linux') !== false) return 'Linux';
        if (strpos($ua, 'Android') !== false) return 'Android';
        if (strpos($ua, 'iOS') !== false || strpos($ua, 'iPhone') !== false) return 'iOS';
        
        return 'Unknown';
    }
}
EOF

print_success "Model files created"

# ============================================
# REPOSITORY FILES
# ============================================
print_header "Creating Repository files"

cat > app/Repositories/Contracts/UrlRepositoryInterface.php << 'EOF'
<?php

namespace App\Repositories\Contracts;

interface UrlRepositoryInterface
{
    public function findById($id);
    public function findByShortCode($shortCode);
    public function findByUserId($userId, $limit = 50, $offset = 0);
    public function create(array $data);
    public function update($id, array $data);
    public function delete($id);
    public function incrementClicks($id);
    public function getTotalCount($userId = null);
    public function getTopLinks($limit = 10);
    public function search($keyword, $limit = 50);
}
EOF

cat > app/Repositories/UrlRepository.php << 'EOF'
<?php

namespace App\Repositories;

use App\Repositories\Contracts\UrlRepositoryInterface;
use App\Models\Url;
use PDO;

class UrlRepository implements UrlRepositoryInterface
{
    private $db;
    
    public function __construct($db)
    {
        $this->db = $db;
    }
    
    public function findById($id)
    {
        $sql = "SELECT * FROM links WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':id' => $id]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new Url($data) : null;
    }
    
    public function findByShortCode($shortCode)
    {
        $sql = "SELECT * FROM links WHERE short_code = :short_code";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':short_code' => $shortCode]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new Url($data) : null;
    }
    
    public function findByUserId($userId, $limit = 50, $offset = 0)
    {
        $sql = "SELECT * FROM links WHERE user_id = :user_id 
                ORDER BY created_at DESC LIMIT :limit OFFSET :offset";
        $stmt = $this->db->prepare($sql);
        $stmt->bindValue(':user_id', $userId, PDO::PARAM_INT);
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
        $stmt->execute();
        
        $urls = [];
        while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $urls[] = new Url($data);
        }
        
        return $urls;
    }
    
    public function create(array $data)
    {
        $sql = "INSERT INTO links (title, short_code, original_url, original_domain, user_id, 
                expires_at, created_ip, display_order, link_order) 
                VALUES (:title, :short_code, :original_url, :original_domain, :user_id, 
                :expires_at, :created_ip, :display_order, :link_order)";
        
        $stmt = $this->db->prepare($sql);
        
        $domain = parse_url($data['original_url'], PHP_URL_HOST);
        
        $stmt->execute([
            ':title' => $data['title'] ?? null,
            ':short_code' => $data['short_code'],
            ':original_url' => $data['original_url'],
            ':original_domain' => $domain,
            ':user_id' => $data['user_id'] ?? null,
            ':expires_at' => $data['expires_at'] ?? null,
            ':created_ip' => $data['created_ip'] ?? null,
            ':display_order' => $data['display_order'] ?? 0,
            ':link_order' => $data['link_order'] ?? 0,
        ]);
        
        return $this->db->lastInsertId();
    }
    
    public function update($id, array $data)
    {
        $fields = [];
        $params = [':id' => $id];
        
        $allowedFields = ['title', 'original_url', 'expires_at', 'is_active', 
                          'last_edited_at', 'last_edited_ip', 'last_edited_by',
                          'display_order', 'link_order'];
        
        foreach ($allowedFields as $field) {
            if (isset($data[$field])) {
                $fields[] = "$field = :$field";
                $params[":$field"] = $data[$field];
            }
        }
        
        if (empty($fields)) {
            return false;
        }
        
        $sql = "UPDATE links SET " . implode(', ', $fields) . " WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute($params);
    }
    
    public function delete($id)
    {
        $sql = "DELETE FROM links WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute([':id' => $id]);
    }
    
    public function incrementClicks($id)
    {
        $sql = "UPDATE links SET clicks = clicks + 1 WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute([':id' => $id]);
    }
    
    public function getTotalCount($userId = null)
    {
        if ($userId) {
            $sql = "SELECT COUNT(*) FROM links WHERE user_id = :user_id";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([':user_id' => $userId]);
        } else {
            $sql = "SELECT COUNT(*) FROM links";
            $stmt = $this->db->prepare($sql);
            $stmt->execute();
        }
        
        return (int)$stmt->fetchColumn();
    }
    
    public function getTopLinks($limit = 10)
    {
        $sql = "SELECT * FROM links WHERE is_active = 1 
                ORDER BY clicks DESC LIMIT :limit";
        $stmt = $this->db->prepare($sql);
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->execute();
        
        $urls = [];
        while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $urls[] = new Url($data);
        }
        
        return $urls;
    }
    
    public function search($keyword, $limit = 50)
    {
        $sql = "SELECT * FROM links WHERE original_url LIKE :keyword 
                OR title LIKE :keyword OR short_code LIKE :keyword 
                LIMIT :limit";
        $stmt = $this->db->prepare($sql);
        $keyword = "%{$keyword}%";
        $stmt->bindValue(':keyword', $keyword, PDO::PARAM_STR);
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->execute();
        
        $urls = [];
        while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $urls[] = new Url($data);
        }
        
        return $urls;
    }
}
EOF

cat > app/Repositories/UserRepository.php << 'EOF'
<?php

namespace App\Repositories;

use App\Models\User;
use PDO;

class UserRepository
{
    private $db;
    
    public function __construct($db)
    {
        $this->db = $db;
    }
    
    public function findById($id)
    {
        $sql = "SELECT * FROM users WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':id' => $id]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new User($data) : null;
    }
    
    public function findByEmail($email)
    {
        $sql = "SELECT * FROM users WHERE email = :email";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':email' => $email]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new User($data) : null;
    }
    
    public function findByApiKey($apiKey)
    {
        $sql = "SELECT * FROM users WHERE api_key = :api_key";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':api_key' => $apiKey]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new User($data) : null;
    }
    
    public function create(array $data)
    {
        $sql = "INSERT INTO users (name, email, password, api_key, email_verified, verification_token) 
                VALUES (:name, :email, :password, :api_key, :email_verified, :verification_token)";
        
        $stmt = $this->db->prepare($sql);
        $stmt->execute([
            ':name' => $data['name'],
            ':email' => $data['email'],
            ':password' => $data['password'],
            ':api_key' => $data['api_key'] ?? bin2hex(random_bytes(32)),
            ':email_verified' => $data['email_verified'] ?? 0,
            ':verification_token' => $data['verification_token'] ?? null,
        ]);
        
        return $this->db->lastInsertId();
    }
    
    public function update($id, array $data)
    {
        $fields = [];
        $params = [':id' => $id];
        
        $allowedFields = ['name', 'password', 'email_verified', 'verification_token', 
                          'reset_token', 'reset_token_expires', 'last_login_at', 
                          'last_login_ip', 'is_active', 'api_key'];
        
        foreach ($allowedFields as $field) {
            if (isset($data[$field])) {
                $fields[] = "$field = :$field";
                $params[":$field"] = $data[$field];
            }
        }
        
        if (empty($fields)) {
            return false;
        }
        
        $sql = "UPDATE users SET " . implode(', ', $fields) . ", updated_at = NOW() WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute($params);
    }
    
    public function updateLastLogin($id, $ip)
    {
        $sql = "UPDATE users SET last_login_at = NOW(), last_login_ip = :ip WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute([':id' => $id, ':ip' => $ip]);
    }
    
    public function verifyEmail($token)
    {
        $sql = "UPDATE users SET email_verified = 1, verification_token = NULL 
                WHERE verification_token = :token";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute([':token' => $token]) && $stmt->rowCount() > 0;
    }
    
    public function delete($id)
    {
        $sql = "DELETE FROM users WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute([':id' => $id]);
    }
}
EOF

print_success "Repository files created"

# ============================================
# SERVICE FILES
# ============================================
print_header "Creating Service files"

cat > app/Services/ShortCodeGenerator.php << 'EOF'
<?php

namespace App\Services;

class ShortCodeGenerator
{
    private $characters;
    private $length;
    
    public function __construct($length = 6, $characters = null)
    {
        $this->length = $length;
        $this->characters = $characters ?: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    }
    
    public function generate()
    {
        $code = '';
        $max = strlen($this->characters) - 1;
        
        for ($i = 0; $i < $this->length; $i++) {
            $code .= $this->characters[random_int(0, $max)];
        }
        
        return $code;
    }
    
    public function generateUnique($callback, $maxAttempts = 10)
    {
        $attempts = 0;
        
        do {
            $code = $this->generate();
            $attempts++;
            
            if ($attempts > $maxAttempts) {
                $this->length++;
                $attempts = 0;
            }
        } while ($callback($code));
        
        return $code;
    }
    
    public function setLength($length)
    {
        $this->length = $length;
        return $this;
    }
    
    public function isValid($code)
    {
        return preg_match('/^[a-zA-Z0-9]+$/', $code) === 1;
    }
}
EOF

cat > app/Services/UrlService.php << 'EOF'
<?php

namespace App\Services;

use App\Repositories\Contracts\UrlRepositoryInterface;
use App\DTO\CreateUrlDTO;
use App\Models\Url;

class UrlService
{
    private $urlRepository;
    private $shortCodeGenerator;
    
    public function __construct(UrlRepositoryInterface $urlRepository, ShortCodeGenerator $shortCodeGenerator)
    {
        $this->urlRepository = $urlRepository;
        $this->shortCodeGenerator = $shortCodeGenerator;
    }
    
    public function createShortUrl(CreateUrlDTO $dto)
    {
        $dto->validate();
        
        if ($dto->customShortCode) {
            if (!$this->shortCodeGenerator->isValid($dto->customShortCode)) {
                throw new \InvalidArgumentException('Custom short code can only contain letters and numbers');
            }
            
            $existing = $this->urlRepository->findByShortCode($dto->customShortCode);
            if ($existing) {
                throw new \InvalidArgumentException('Custom short code is already taken');
            }
            $shortCode = $dto->customShortCode;
        } else {
            $shortCode = $this->shortCodeGenerator->generateUnique(function($code) {
                return $this->urlRepository->findByShortCode($code) !== null;
            });
        }
        
        $data = [
            'title' => $dto->title,
            'short_code' => $shortCode,
            'original_url' => $dto->originalUrl,
            'user_id' => $dto->userId,
            'expires_at' => $dto->expiresAt,
            'created_ip' => $dto->createdIp,
        ];
        
        $id = $this->urlRepository->create($data);
        
        return $this->urlRepository->findById($id);
    }
    
    public function getOriginalUrl($shortCode)
    {
        $url = $this->urlRepository->findByShortCode($shortCode);
        
        if (!$url) {
            throw new \Exception('URL not found', 404);
        }
        
        if (!$url->canAccess()) {
            throw new \Exception('Link is inactive or expired', 403);
        }
        
        $this->urlRepository->incrementClicks($url->id);
        
        return $url->originalUrl;
    }
    
    public function updateUrl($id, array $data, $userId = null)
    {
        $url = $this->urlRepository->findById($id);
        
        if (!$url) {
            throw new \Exception('URL not found', 404);
        }
        
        if ($userId && $url->userId != $userId) {
            throw new \Exception('Unauthorized', 403);
        }
        
        $updateData = [
            'last_edited_at' => date('Y-m-d H:i:s'),
            'last_edited_ip' => $_SERVER['REMOTE_ADDR'] ?? null,
            'last_edited_by' => $userId,
        ];
        
        $allowedFields = ['title', 'original_url', 'expires_at', 'is_active', 'display_order', 'link_order'];
        
        foreach ($allowedFields as $field) {
            if (isset($data[$field])) {
                if ($field === 'original_url' && !filter_var($data[$field], FILTER_VALIDATE_URL)) {
                    throw new \InvalidArgumentException('Invalid URL provided');
                }
                $updateData[$field] = $data[$field];
            }
        }
        
        return $this->urlRepository->update($id, $updateData);
    }
    
    public function deleteUrl($id, $userId = null)
    {
        $url = $this->urlRepository->findById($id);
        
        if (!$url) {
            throw new \Exception('URL not found', 404);
        }
        
        if ($userId && $url->userId != $userId) {
            throw new \Exception('Unauthorized', 403);
        }
        
        return $this->urlRepository->delete($id);
    }
    
    public function getUserUrls($userId, $page = 1, $perPage = 20)
    {
        $offset = ($page - 1) * $perPage;
        $urls = $this->urlRepository->findByUserId($userId, $perPage, $offset);
        $total = $this->urlRepository->getTotalCount($userId);
        
        return [
            'data' => $urls,
            'total' => $total,
            'page' => $page,
            'per_page' => $perPage,
            'last_page' => ceil($total / $perPage),
        ];
    }
    
    public function getUrlInfo($shortCode)
    {
        $url = $this->urlRepository->findByShortCode($shortCode);
        
        if (!$url) {
            throw new \Exception('URL not found', 404);
        }
        
        return $url;
    }
    
    public function getTopUrls($limit = 10)
    {
        return $this->urlRepository->getTopLinks($limit);
    }
}
EOF

cat > app/Services/AnalyticsService.php << 'EOF'
<?php

namespace App\Services;

use PDO;
use App\Models\Click;

class AnalyticsService
{
    private $db;
    
    public function __construct($db)
    {
        $this->db = $db;
    }
    
    public function trackClick($linkId, $ip, $userAgent, $referer = null)
    {
        $click = new Click([
            'link_id' => $linkId,
            'ip_address' => $ip,
            'user_agent' => $userAgent,
            'referer' => $referer,
        ]);
        
        $deviceType = $click->detectDevice();
        $browser = $click->detectBrowser();
        $os = $click->detectOS();
        
        $sql = "INSERT INTO clicks (link_id, ip_address, user_agent, referer, device_type, browser, os, clicked_at) 
                VALUES (:link_id, :ip, :ua, :ref, :device, :browser, :os, NOW())";
        
        $stmt = $this->db->prepare($sql);
        return $stmt->execute([
            ':link_id' => $linkId,
            ':ip' => $ip,
            ':ua' => $userAgent,
            ':ref' => $referer,
            ':device' => $deviceType,
            ':browser' => $browser,
            ':os' => $os,
        ]);
    }
    
    public function getStats($linkId)
    {
        $sql = "SELECT 
                    COUNT(*) as total_clicks,
                    COUNT(DISTINCT ip_address) as unique_visitors,
                    COUNT(DISTINCT DATE(clicked_at)) as days_active
                FROM clicks 
                WHERE link_id = :link_id";
        
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':link_id' => $linkId]);
        $basic = $stmt->fetch(PDO::FETCH_ASSOC);
        
        $sql = "SELECT device_type, COUNT(*) as count 
                FROM clicks WHERE link_id = :link_id 
                GROUP BY device_type";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':link_id' => $linkId]);
        $devices = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $sql = "SELECT browser, COUNT(*) as count 
                FROM clicks WHERE link_id = :link_id 
                GROUP BY browser";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':link_id' => $linkId]);
        $browsers = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $sql = "SELECT DATE(clicked_at) as date, COUNT(*) as clicks 
                FROM clicks WHERE link_id = :link_id 
                GROUP BY DATE(clicked_at) 
                ORDER BY date DESC LIMIT 30";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':link_id' => $linkId]);
        $daily = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        return [
            'total_clicks' => (int)$basic['total_clicks'],
            'unique_visitors' => (int)$basic['unique_visitors'],
            'days_active' => (int)$basic['days_active'],
            'devices' => $devices,
            'browsers' => $browsers,
            'daily_clicks' => $daily,
        ];
    }
    
    public function getGlobalStats()
    {
        $sql = "SELECT 
                    (SELECT COUNT(*) FROM links) as total_links,
                    (SELECT SUM(clicks) FROM links) as total_clicks,
                    (SELECT COUNT(*) FROM users) as total_users,
                    (SELECT COUNT(*) FROM clicks WHERE clicked_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)) as clicks_last_24h";
        
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
}
EOF

print_success "Service files created"

# ============================================
# CONTROLLER FILES
# ============================================
print_header "Creating Controller files"

cat > app/Controllers/UrlController.php << 'EOF'
<?php

namespace App\Controllers;

use App\Services\UrlService;
use App\DTO\CreateUrlDTO;
use App\DTO\UrlResponseDTO;

class UrlController
{
    private $urlService;
    private $baseUrl;
    
    public function __construct(UrlService $urlService)
    {
        $this->urlService = $urlService;
        $this->baseUrl = getenv('APP_URL') ?: 'http://id.polasaja.com';
    }
    
    public function create()
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(HTTP_METHOD_NOT_ALLOWED);
            echo json_encode(['error' => 'Method not allowed']);
            return;
        }
        
        $input = json_decode(file_get_contents('php://input'), true);
        
        if (!$input || !isset($input['url'])) {
            http_response_code(HTTP_BAD_REQUEST);
            echo json_encode(['error' => 'URL is required']);
            return;
        }
        
        try {
            $dto = new CreateUrlDTO([
                'original_url' => $input['url'],
                'title' => $input['title'] ?? null,
                'custom_short_code' => $input['custom_code'] ?? null,
                'user_id' => $_SESSION[SESSION_USER_ID] ?? null,
            ]);
            
            $url = $this->urlService->createShortUrl($dto);
            $response = new UrlResponseDTO($url->toArray(), $this->baseUrl);
            
            echo json_encode([
                'success' => true,
                'data' => $response->toArray()
            ]);
            
        } catch (\InvalidArgumentException $e) {
            http_response_code(HTTP_BAD_REQUEST);
            echo json_encode(['success' => false, 'error' => $e->getMessage()]);
        } catch (\Exception $e) {
            http_response_code(HTTP_INTERNAL_SERVER_ERROR);
            echo json_encode(['success' => false, 'error' => 'Internal server error']);
        }
    }
    
    public function index()
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
            http_response_code(HTTP_METHOD_NOT_ALLOWED);
            return;
        }
        
        $userId = $_SESSION[SESSION_USER_ID] ?? null;
        $page = (int)($_GET['page'] ?? 1);
        
        try {
            $result = $this->urlService->getUserUrls($userId, $page);
            
            $data = array_map(function($url) {
                return (new UrlResponseDTO($url->toArray(), $this->baseUrl))->toArray();
            }, $result['data']);
            
            echo json_encode([
                'success' => true,
                'data' => $data,
                'pagination' => [
                    'current_page' => $result['page'],
                    'per_page' => $result['per_page'],
                    'total' => $result['total'],
                    'last_page' => $result['last_page'],
                ]
            ]);
        } catch (\Exception $e) {
            http_response_code(HTTP_INTERNAL_SERVER_ERROR);
            echo json_encode(['success' => false, 'error' => $e->getMessage()]);
        }
    }
    
    public function show($id)
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
            http_response_code(HTTP_METHOD_NOT_ALLOWED);
            return;
        }
        
        try {
            $url = $this->urlService->getUrlInfo($id);
            $response = new UrlResponseDTO($url->toArray(), $this->baseUrl);
            
            echo json_encode([
                'success' => true,
                'data' => $response->toArray()
            ]);
        } catch (\Exception $e) {
            http_response_code(HTTP_NOT_FOUND);
            echo json_encode(['success' => false, 'error' => $e->getMessage()]);
        }
    }
    
    public function update($id)
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'PUT') {
            http_response_code(HTTP_METHOD_NOT_ALLOWED);
            return;
        }
        
        $userId = $_SESSION[SESSION_USER_ID] ?? null;
        $input = json_decode(file_get_contents('php://input'), true);
        
        try {
            $this->urlService->updateUrl($id, $input, $userId);
            
            echo json_encode(['success' => true, 'message' => 'URL updated successfully']);
        } catch (\Exception $e) {
            http_response_code($e->getCode() ?: HTTP_INTERNAL_SERVER_ERROR);
            echo json_encode(['success' => false, 'error' => $e->getMessage()]);
        }
    }
    
    public function delete($id)
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'DELETE') {
            http_response_code(HTTP_METHOD_NOT_ALLOWED);
            return;
        }
        
        $userId = $_SESSION[SESSION_USER_ID] ?? null;
        
        try {
            $this->urlService->deleteUrl($id, $userId);
            
            echo json_encode(['success' => true, 'message' => 'URL deleted successfully']);
        } catch (\Exception $e) {
            http_response_code($e->getCode() ?: HTTP_INTERNAL_SERVER_ERROR);
            echo json_encode(['success' => false, 'error' => $e->getMessage()]);
        }
    }
}
EOF

cat > app/Controllers/RedirectController.php << 'EOF'
<?php

namespace App\Controllers;

use App\Services\UrlService;
use App\Services\AnalyticsService;

class RedirectController
{
    private $urlService;
    private $analyticsService;
    
    public function __construct(UrlService $urlService, AnalyticsService $analyticsService)
    {
        $this->urlService = $urlService;
        $this->analyticsService = $analyticsService;
    }
    
    public function redirect($shortCode)
    {
        try {
            $url = $this->urlService->getUrlInfo($shortCode);
            $originalUrl = $this->urlService->getOriginalUrl($shortCode);
            
            // Track click
            $this->analyticsService->trackClick(
                $url->id,
                $_SERVER['REMOTE_ADDR'] ?? null,
                $_SERVER['HTTP_USER_AGENT'] ?? null,
                $_SERVER['HTTP_REFERER'] ?? null
            );
            
            header("Location: $originalUrl", true, 302);
            exit;
            
        } catch (\Exception $e) {
            http_response_code($e->getCode() ?: HTTP_NOT_FOUND);
            
            $this->showErrorPage($e->getMessage(), $shortCode ?? null);
        }
    }
    
    private function showErrorPage($message, $shortCode = null)
    {
        $baseUrl = getenv('APP_URL') ?: 'http://id.polasaja.com';
        
        echo '<!DOCTYPE html>
        <html>
        <head>
            <title>Link Not Found - PolaSaja</title>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <style>
                *{margin:0;padding:0;box-sizing:border-box}
                body{font-family:Arial,sans-serif;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);min-height:100vh;display:flex;align-items:center;justify-content:center}
                .container{background:white;border-radius:20px;padding:40px;box-shadow:0 20px 60px rgba(0,0,0,0.3);max-width:500px;width:90%;text-align:center}
                h1{font-size:72px;color:#667eea;margin-bottom:20px}
                h2{color:#333;margin-bottom:10px}
                p{color:#666;margin-bottom:30px}
                a{display:inline-block;padding:12px 30px;background:#667eea;color:white;text-decoration:none;border-radius:10px;font-weight:bold}
                a:hover{background:#5a67d8}
                .code{background:#f0f0f0;padding:10px;border-radius:8px;font-family:monospace;margin:20px 0}
            </style>
        </head>
        <body>
            <div class="container">
                <h1>🔗</h1>
                <h2>Link Not Found</h2>
                <p>' . htmlspecialchars($message) . '</p>';
        
        if ($shortCode) {
            echo '<div class="code">' . $baseUrl . '/' . htmlspecialchars($shortCode) . '</div>';
        }
        
        echo '      <a href="' . $baseUrl . '">Go to Homepage</a>
            </div>
        </body>
        </html>';
    }
}
EOF

cat > app/Controllers/ApiController.php << 'EOF'
<?php

namespace App\Controllers;

use App\Services\UrlService;
use App\Services\AnalyticsService;
use App\DTO\CreateUrlDTO;
use App\DTO\UrlResponseDTO;

class ApiController
{
    private $urlService;
    private $analyticsService;
    private $baseUrl;
    
    public function __construct(UrlService $urlService, AnalyticsService $analyticsService)
    {
        $this->urlService = $urlService;
        $this->analyticsService = $analyticsService;
        $this->baseUrl = getenv('APP_URL') ?: 'http://id.polasaja.com';
    }
    
    public function shorten()
    {
        $this->enableCors();
        
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            $this->jsonResponse(['error' => 'Method not allowed'], HTTP_METHOD_NOT_ALLOWED);
            return;
        }
        
        $input = json_decode(file_get_contents('php://input'), true);
        
        if (!$input || !isset($input['url'])) {
            $this->jsonResponse(['error' => 'URL is required'], HTTP_BAD_REQUEST);
            return;
        }
        
        try {
            $dto = new CreateUrlDTO([
                'original_url' => $input['url'],
                'title' => $input['title'] ?? null,
                'custom_short_code' => $input['custom_code'] ?? null,
                'user_id' => $this->getApiUserId(),
            ]);
            
            $url = $this->urlService->createShortUrl($dto);
            $response = new UrlResponseDTO($url->toArray(), $this->baseUrl);
            
            $this->jsonResponse([
                'success' => true,
                'data' => $response->toArray()
            ], HTTP_CREATED);
            
        } catch (\Exception $e) {
            $this->jsonResponse(['error' => $e->getMessage()], HTTP_BAD_REQUEST);
        }
    }
    
    public function stats($shortCode = null)
    {
        $this->enableCors();
        
        if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
            $this->jsonResponse(['error' => 'Method not allowed'], HTTP_METHOD_NOT_ALLOWED);
            return;
        }
        
        try {
            if ($shortCode) {
                $url = $this->urlService->getUrlInfo($shortCode);
                $stats = $this->analyticsService->getStats($url->id);
                
                $this->jsonResponse([
                    'success' => true,
                    'data' => [
                        'url' => (new UrlResponseDTO($url->toArray(), $this->baseUrl))->toArray(),
                        'analytics' => $stats
                    ]
                ]);
            } else {
                $globalStats = $this->analyticsService->getGlobalStats();
                $topUrls = $this->urlService->getTopUrls(10);
                
                $topUrlsData = array_map(function($url) {
                    return (new UrlResponseDTO($url->toArray(), $this->baseUrl))->toArray();
                }, $topUrls);
                
                $this->jsonResponse([
                    'success' => true,
                    'data' => [
                        'global' => $globalStats,
                        'top_urls' => $topUrlsData
                    ]
                ]);
            }
        } catch (\Exception $e) {
            $this->jsonResponse(['error' => $e->getMessage()], HTTP_NOT_FOUND);
        }
    }
    
    public function info($shortCode)
    {
        $this->enableCors();
        
        if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
            $this->jsonResponse(['error' => 'Method not allowed'], HTTP_METHOD_NOT_ALLOWED);
            return;
        }
        
        try {
            $url = $this->urlService->getUrlInfo($shortCode);
            $response = new UrlResponseDTO($url->toArray(), $this->baseUrl);
            
            $this->jsonResponse([
                'success' => true,
                'data' => $response->toArray()
            ]);
        } catch (\Exception $e) {
            $this->jsonResponse(['error' => $e->getMessage()], HTTP_NOT_FOUND);
        }
    }
    
    private function getApiUserId()
    {
        // Check for API key in headers
        $headers = getallheaders();
        $apiKey = $headers['X-API-Key'] ?? null;
        
        if ($apiKey) {
            $userRepo = new \App\Repositories\UserRepository($GLOBALS['db']);
            $user = $userRepo->findByApiKey($apiKey);
            return $user ? $user->id : null;
        }
        
        return $_SESSION[SESSION_USER_ID] ?? null;
    }
    
    private function enableCors()
    {
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
        header('Access-Control-Allow-Headers: Content-Type, X-API-Key, Authorization');
        
        if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            exit(0);
        }
    }
    
    private function jsonResponse($data, $statusCode = HTTP_OK)
    {
        http_response_code($statusCode);
        header('Content-Type: application/json');
        echo json_encode($data);
        exit;
    }
}
EOF

print_success "Controller files created"

# ============================================
# MIDDLEWARE FILES
# ============================================
print_header "Creating Middleware files"

cat > app/Middleware/AuthMiddleware.php << 'EOF'
<?php

namespace App\Middleware;

class AuthMiddleware
{
    public function handle()
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
        
        if (!isset($_SESSION[SESSION_USER_ID])) {
            http_response_code(HTTP_UNAUTHORIZED);
            
            if ($this->isApiRequest()) {
                header('Content-Type: application/json');
                echo json_encode(['error' => 'Unauthorized', 'message' => 'Please login first']);
            } else {
                header('Location: /login');
            }
            exit;
        }
        
        return true;
    }
    
    public function requireAdmin()
    {
        $this->handle();
        
        if ($_SESSION[SESSION_USER_ROLE] !== ROLE_ADMIN) {
            http_response_code(HTTP_FORBIDDEN);
            
            if ($this->isApiRequest()) {
                header('Content-Type: application/json');
                echo json_encode(['error' => 'Forbidden', 'message' => 'Admin access required']);
            } else {
                echo "<h1>403 Forbidden</h1><p>You don't have permission to access this resource.</p>";
            }
            exit;
        }
        
        return true;
    }
    
    private function isApiRequest()
    {
        return strpos($_SERVER['REQUEST_URI'], '/api/') === 0;
    }
}
EOF

cat > app/Middleware/RateLimitMiddleware.php << 'EOF'
<?php

namespace App\Middleware;

class RateLimitMiddleware
{
    private $db;
    private $maxRequests;
    private $timeWindow;
    
    public function __construct($db, $maxRequests = 60, $timeWindow = 60)
    {
        $this->db = $db;
        $this->maxRequests = $maxRequests;
        $this->timeWindow = $timeWindow;
    }
    
    public function handle()
    {
        $enabled = getenv('RATE_LIMIT_ENABLED') === 'true';
        if (!$enabled) {
            return true;
        }
        
        $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
        $currentTime = time();
        $windowStart = $currentTime - $this->timeWindow;
        
        // Create rate limit table if not exists
        $this->createTableIfNotExists();
        
        // Clean old records
        $this->cleanOldRecords($windowStart);
        
        // Count requests in current window
        $stmt = $this->db->prepare("
            SELECT COUNT(*) FROM rate_limits 
            WHERE ip_address = :ip AND request_time > :window_start
        ");
        $stmt->execute([
            ':ip' => $ip,
            ':window_start' => date('Y-m-d H:i:s', $windowStart)
        ]);
        
        $count = $stmt->fetchColumn();
        
        if ($count >= $this->maxRequests) {
            http_response_code(HTTP_TOO_MANY_REQUESTS);
            header('Content-Type: application/json');
            echo json_encode([
                'error' => 'Too Many Requests',
                'message' => "Rate limit exceeded. Maximum {$this->maxRequests} requests per {$this->timeWindow} seconds.",
                'retry_after' => $this->timeWindow
            ]);
            exit;
        }
        
        // Log this request
        $stmt = $this->db->prepare("
            INSERT INTO rate_limits (ip_address, request_uri, request_method, request_time) 
            VALUES (:ip, :uri, :method, NOW())
        ");
        $stmt->execute([
            ':ip' => $ip,
            ':uri' => $_SERVER['REQUEST_URI'] ?? '',
            ':method' => $_SERVER['REQUEST_METHOD'] ?? ''
        ]);
        
        return true;
    }
    
    private function createTableIfNotExists()
    {
        $sql = "CREATE TABLE IF NOT EXISTS rate_limits (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            ip_address VARCHAR(45) NOT NULL,
            request_uri VARCHAR(500),
            request_method VARCHAR(10),
            request_time DATETIME NOT NULL,
            INDEX idx_ip_time (ip_address, request_time)
        )";
        
        $this->db->exec($sql);
    }
    
    private function cleanOldRecords($windowStart)
    {
        $stmt = $this->db->prepare("
            DELETE FROM rate_limits WHERE request_time < :window_start
        ");
        $stmt->execute([':window_start' => date('Y-m-d H:i:s', $windowStart)]);
    }
}
EOF

cat > app/Middleware/CorsMiddleware.php << 'EOF'
<?php

namespace App\Middleware;

class CorsMiddleware
{
    private $allowedOrigins = ['*'];
    private $allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'];
    private $allowedHeaders = ['Content-Type', 'X-API-Key', 'Authorization'];
    
    public function handle()
    {
        $origin = $_SERVER['HTTP_ORIGIN'] ?? '*';
        
        if (in_array('*', $this->allowedOrigins) || in_array($origin, $this->allowedOrigins)) {
            header("Access-Control-Allow-Origin: $origin");
        }
        
        header('Access-Control-Allow-Methods: ' . implode(', ', $this->allowedMethods));
        header('Access-Control-Allow-Headers: ' . implode(', ', $this->allowedHeaders));
        header('Access-Control-Allow-Credentials: true');
        
        if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            http_response_code(200);
            exit;
        }
        
        return true;
    }
    
    public function setAllowedOrigins($origins)
    {
        $this->allowedOrigins = $origins;
        return $this;
    }
}
EOF

print_success "Middleware files created"

# ============================================
# BOOTSTRAP FILES
# ============================================
print_header "Creating bootstrap files"

cat > bootstrap/autoload.php << 'EOF'
<?php

/**
 * Simple autoloader for the application
 */

spl_autoload_register(function ($class) {
    $prefix = 'App\\';
    $base_dir = __DIR__ . '/../app/';
    
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        return;
    }
    
    $relative_class = substr($class, $len);
    $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
    
    if (file_exists($file)) {
        require $file;
        return true;
    }
    return false;
});

// Load constants
require_once __DIR__ . '/../config/constants.php';

// Load helper functions
$helperFile = __DIR__ . '/../app/Helpers/functions.php';
if (file_exists($helperFile)) {
    require_once $helperFile;
}
EOF

cat > bootstrap/app.php << 'EOF'
<?php

require_once __DIR__ . '/autoload.php';

use App\Repositories\UrlRepository;
use App\Repositories\UserRepository;
use App\Services\UrlService;
use App\Services\ShortCodeGenerator;
use App\Services\AnalyticsService;
use App\Middleware\RateLimitMiddleware;
use App\Middleware\CorsMiddleware;

class Application
{
    private static $instance;
    private $db;
    private $config = [];
    private $container = [];
    
    public function __construct()
    {
        $this->loadEnvironment();
        $this->loadConfig();
        $this->initializeDatabase();
        $this->registerServices();
        $this->startSession();
    }
    
    public static function getInstance()
    {
        if (!self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function loadEnvironment()
    {
        $envFile = __DIR__ . '/../.env';
        if (file_exists($envFile)) {
            $lines = file($envFile);
            foreach ($lines as $line) {
                $line = trim($line);
                if ($line && !str_starts_with($line, '#')) {
                    putenv($line);
                    
                    // Also set $_ENV
                    if (strpos($line, '=') !== false) {
                        list($key, $value) = explode('=', $line, 2);
                        $_ENV[$key] = $value;
                    }
                }
            }
        }
    }
    
    private function loadConfig()
    {
        $configFiles = ['app', 'database', 'cache'];
        foreach ($configFiles as $file) {
            $path = __DIR__ . '/../config/' . $file . '.php';
            if (file_exists($path)) {
                $this->config[$file] = require $path;
            }
        }
    }
    
    private function initializeDatabase()
    {
        $config = $this->config['database']['connections']['mysql'] ?? [];
        
        try {
            $dsn = sprintf(
                "mysql:host=%s;port=%s;dbname=%s;charset=%s",
                $config['host'],
                $config['port'],
                $config['database'],
                $config['charset']
            );
            
            $this->db = new PDO($dsn, $config['username'], $config['password'], [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ]);
            
            // Make db available globally
            $GLOBALS['db'] = $this->db;
            
        } catch (PDOException $e) {
            if ($this->config['app']['debug']) {
                die("Database connection failed: " . $e->getMessage());
            } else {
                die("Database connection failed. Please check your configuration.");
            }
        }
    }
    
    private function registerServices()
    {
        $this->container['urlRepository'] = new UrlRepository($this->db);
        $this->container['userRepository'] = new UserRepository($this->db);
        $this->container['shortCodeGenerator'] = new ShortCodeGenerator(
            $this->config['app']['short_code']['length'],
            $this->config['app']['short_code']['chars']
        );
        $this->container['urlService'] = new UrlService(
            $this->container['urlRepository'],
            $this->container['shortCodeGenerator']
        );
        $this->container['analyticsService'] = new AnalyticsService($this->db);
        $this->container['rateLimitMiddleware'] = new RateLimitMiddleware(
            $this->db,
            $this->config['app']['rate_limit']['per_minute'] ?? 60
        );
        $this->container['corsMiddleware'] = new CorsMiddleware();
    }
    
    private function startSession()
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
    }
    
    public function getDb()
    {
        return $this->db;
    }
    
    public function getConfig($key = null)
    {
        if ($key === null) {
            return $this->config;
        }
        
        $parts = explode('.', $key);
        $config = $this->config;
        
        foreach ($parts as $part) {
            if (!isset($config[$part])) {
                return null;
            }
            $config = $config[$part];
        }
        
        return $config;
    }
    
    public function get($service)
    {
        return $this->container[$service] ?? null;
    }
    
    public function run()
    {
        $this->handleRequest();
    }
    
    private function handleRequest()
    {
        $uri = $_SERVER['REQUEST_URI'];
        $method = $_SERVER['REQUEST_METHOD'];
        $uri = strtok($uri, '?');
        
        // Apply CORS middleware for API routes
        if (strpos($uri, '/api/') === 0) {
            $this->container['corsMiddleware']->handle();
        }
        
        // Apply rate limiting
        if ($this->config['app']['rate_limit']['enabled']) {
            $this->container['rateLimitMiddleware']->handle();
        }
        
        // Define routes
        $routes = $this->getRoutes();
        
        foreach ($routes as $route) {
            if ($route['method'] === $method && preg_match($route['pattern'], $uri, $matches)) {
                array_shift($matches);
                $this->callController($route['controller'], $route['action'], $matches);
                return;
            }
        }
        
        // Handle 404
        http_response_code(HTTP_NOT_FOUND);
        
        if (strpos($uri, '/api/') === 0) {
            header('Content-Type: application/json');
            echo json_encode(['error' => 'Endpoint not found']);
        } else {
            $this->render404();
        }
    }
    
    private function getRoutes()
    {
        return [
            ['method' => 'GET', 'pattern' => '#^/$#', 'controller' => 'HomeController', 'action' => 'index'],
            ['method' => 'POST', 'pattern' => '#^/api/shorten$#', 'controller' => 'ApiController', 'action' => 'shorten'],
            ['method' => 'GET', 'pattern' => '#^/api/stats$#', 'controller' => 'ApiController', 'action' => 'stats'],
            ['method' => 'GET', 'pattern' => '#^/api/stats/([a-zA-Z0-9]+)$#', 'controller' => 'ApiController', 'action' => 'stats'],
            ['method' => 'GET', 'pattern' => '#^/api/info/([a-zA-Z0-9]+)$#', 'controller' => 'ApiController', 'action' => 'info'],
            ['method' => 'GET', 'pattern' => '#^/([a-zA-Z0-9]+)$#', 'controller' => 'RedirectController', 'action' => 'redirect'],
        ];
    }
    
    private function callController($controllerName, $action, $params = [])
    {
        $controllerClass = "App\\Controllers\\$controllerName";
        
        if (!class_exists($controllerClass)) {
            http_response_code(HTTP_INTERNAL_SERVER_ERROR);
            echo "Controller not found: $controllerClass";
            return;
        }
        
        $controller = new $controllerClass(
            $this->container['urlService'],
            $this->container['analyticsService']
        );
        
        if (!method_exists($controller, $action)) {
            http_response_code(HTTP_INTERNAL_SERVER_ERROR);
            echo "Action not found: $action";
            return;
        }
        
        call_user_func_array([$controller, $action], $params);
    }
    
    private function render404()
    {
        $baseUrl = getenv('APP_URL') ?: 'http://id.polasaja.com';
        
        echo '<!DOCTYPE html>
        <html>
        <head>
            <title>404 - Page Not Found</title>
            <style>
                body{font-family:Arial;text-align:center;padding:50px;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);min-height:100vh;margin:0;display:flex;align-items:center;justify-content:center}
                .container{background:white;border-radius:20px;padding:40px;max-width:500px}
                h1{font-size:72px;color:#667eea;margin:0}
                a{display:inline-block;margin-top:20px;padding:10px 20px;background:#667eea;color:white;text-decoration:none;border-radius:8px}
            </style>
        </head>
        <body>
            <div class="container">
                <h1>404</h1>
                <h2>Page Not Found</h2>
                <p>The page you are looking for does not exist.</p>
                <a href="' . $baseUrl . '">Go Home</a>
            </div>
        </body>
        </html>';
    }
}

// Home Controller
namespace App\Controllers;

class HomeController
{
    private $baseUrl;
    
    public function __construct($urlService, $analyticsService)
    {
        $this->baseUrl = getenv('APP_URL') ?: 'http://id.polasaja.com';
    }
    
    public function index()
    {
        $baseUrl = $this->baseUrl;
        
        echo '<!DOCTYPE html>
        <html>
        <head>
            <title>PolaSaja - URL Shortener</title>
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta name="description" content="Free URL shortener service - shorten your long URLs instantly">
            <style>
                *{margin:0;padding:0;box-sizing:border-box}
                body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);min-height:100vh}
                
                /* Navbar */
                .navbar{background:rgba(255,255,255,0.1);padding:20px;backdrop-filter:blur(10px)}
                .nav-container{max-width:1200px;margin:0 auto;display:flex;justify-content:space-between;align-items:center}
                .logo{font-size:24px;font-weight:bold;color:white}
                .logo span{color:#ffd700}
                .nav-links a{color:white;text-decoration:none;margin-left:30px}
                
                /* Hero */
                .hero{display:flex;align-items:center;justify-content:center;min-height:80vh;padding:20px}
                .container{background:white;border-radius:20px;padding:40px;box-shadow:0 20px 60px rgba(0,0,0,0.3);max-width:600px;width:100%}
                h1{color:#333;margin-bottom:10px;font-size:32px}
                .domain{color:#667eea;font-size:14px;margin-bottom:30px}
                .input-group{display:flex;gap:10px;margin-bottom:20px}
                input{flex:1;padding:15px;border:2px solid #e0e0e0;border-radius:10px;font-size:16px}
                input:focus{outline:none;border-color:#667eea}
                button{padding:15px 30px;background:#667eea;color:white;border:none;border-radius:10px;font-size:16px;cursor:pointer;font-weight:bold}
                button:hover{background:#5a67d8}
                .result{background:#f0fdf4;border:2px solid #86efac;border-radius:10px;padding:20px;margin-top:20px;display:none;word-break:break-all}
                .error{background:#fef2f2;border-color:#fca5a5;color:#dc2626}
                .features{margin-top:40px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}
                .feature{text-align:center;padding:20px}
                .feature h3{color:#333;margin-bottom:10px}
                .feature p{color:#666;font-size:14px}
                .footer{text-align:center;margin-top:40px;padding:20px;color:rgba(255,255,255,0.7)}
                
                @keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
                .spinner{display:inline-block;width:20px;height:20px;border:3px solid rgba(255,255,255,0.3);border-radius:50%;border-top-color:white;animation:spin 0.8s linear infinite;margin-right:10px}
                .loading{opacity:0.5;pointer-events:none}
            </style>
        </head>
        <body>
            <nav class="navbar">
                <div class="nav-container">
                    <div class="logo">Pola<span>Saja</span></div>
                    <div class="nav-links">
                        <a href="/">Home</a>
                        <a href="/api/stats">API</a>
                    </div>
                </div>
            </nav>
            
            <div class="hero">
                <div class="container">
                    <h1>🚀 Shorten Your URLs</h1>
                    <div class="domain">id.polasaja.com</div>
                    <form id="shortenForm">
                        <div class="input-group">
                            <input type="url" id="url" placeholder="https://example.com/very/long/url..." required>
                            <button type="submit" id="submitBtn">Shorten</button>
                        </div>
                    </form>
                    <div class="result" id="result"></div>
                    
                    <div class="features">
                        <div class="feature">
                            <h3>⚡ Fast</h3>
                            <p>Instant short links</p>
                        </div>
                        <div class="feature">
                            <h3>📊 Analytics</h3>
                            <p>Track your clicks</p>
                        </div>
                        <div class="feature">
                            <h3>🔒 Free</h3>
                            <p>No registration required</p>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="footer">
                &copy; 2024 PolaSaja URL Shortener | Free service
            </div>
            
            <script>
                const form = document.getElementById("shortenForm");
                const urlInput = document.getElementById("url");
                const submitBtn = document.getElementById("submitBtn");
                const resultDiv = document.getElementById("result");
                
                form.addEventListener("submit", async (e) => {
                    e.preventDefault();
                    const url = urlInput.value.trim();
                    
                    if (!url) {
                        showError("Please enter a URL");
                        return;
                    }
                    
                    submitBtn.innerHTML = "<span class=\"spinner\"></span> Shortening...";
                    submitBtn.classList.add("loading");
                    resultDiv.style.display = "none";
                    
                    try {
                        const response = await fetch("/api/shorten", {
                            method: "POST",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({ url: url })
                        });
                        
                        const data = await response.json();
                        
                        if (data.success) {
                            resultDiv.className = "result";
                            resultDiv.innerHTML = `
                                <strong>✅ Short URL created!</strong><br><br>
                                <a href="${data.data.short_url}" target="_blank" style="color:#16a34a;font-size:18px">${data.data.short_url}</a>
                                <br><br>
                                <small>🔗 Short code: ${data.data.short_code}</small><br>
                                <small>📊 Total clicks: ${data.data.clicks}</small>
                                <br><br>
                                <button onclick="copyToClipboard(\'${data.data.short_url}\')" style="background:#667eea;color:white;border:none;padding:8px 15px;border-radius:5px;cursor:pointer">📋 Copy URL</button>
                            `;
                            resultDiv.style.display = "block";
                            urlInput.value = "";
                        } else {
                            showError(data.error || "Failed to shorten URL");
                        }
                    } catch (error) {
                        showError("Network error. Please try again.");
                    } finally {
                        submitBtn.innerHTML = "Shorten";
                        submitBtn.classList.remove("loading");
                    }
                });
                
                function showError(message) {
                    resultDiv.className = "result error";
                    resultDiv.innerHTML = "<strong>❌ Error:</strong> " + message;
                    resultDiv.style.display = "block";
                }
                
                function copyToClipboard(text) {
                    navigator.clipboard.writeText(text).then(() => {
                        alert("URL copied to clipboard!");
                    });
                }
            </script>
        </body>
        </html>';
    }
}

// Run the application
$app = Application::getInstance();
$app->run();
EOF

print_success "Bootstrap files created"

# ============================================
# PUBLIC FILES
# ============================================
print_header "Creating public files"

cat > public/index.php << 'EOF'
<?php

// Error reporting based on environment
if (getenv('APP_DEBUG') === 'true') {
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
} else {
    error_reporting(0);
    ini_set('display_errors', 0);
}

// Load the application
require_once __DIR__ . '/../bootstrap/app.php';
EOF

cat > public/.htaccess << 'EOF'
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    
    # Force HTTPS (uncomment if you have SSL)
    # RewriteCond %{HTTPS} off
    # RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
    
    # Redirect to domain id.polasaja.com
    RewriteCond %{HTTP_HOST} !^id\.polasaja\.com$ [NC]
    RewriteRule ^(.*)$ http://id.polasaja.com/$1 [L,R=301]
    
    # Handle front controller
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>

# Security Headers
<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
    Header set X-Frame-Options "DENY"
    Header set X-XSS-Protection "1; mode=block"
    Header set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

# Disable directory listing
Options -Indexes

# Protect sensitive files
<FilesMatch "^\.">
    Order allow,deny
    Deny from all
</FilesMatch>

<FilesMatch "\.(env|log|sqlite|db)$">
    Order allow,deny
    Deny from all
</FilesMatch>
EOF

cat > public/assets/css/app.css << 'EOF'
/* PolaSaja URL Shortener Styles */
:root {
    --primary: #667eea;
    --primary-dark: #5a67d8;
    --secondary: #764ba2;
    --success: #10b981;
    --danger: #ef4444;
    --warning: #f59e0b;
    --dark: #1f2937;
    --light: #f3f4f6;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
    min-height: 100vh;
}

/* Animations */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.fade-in {
    animation: fadeIn 0.5s ease-out;
}

/* Utilities */
.text-center { text-align: center; }
.mt-20 { margin-top: 20px; }
.mb-20 { margin-bottom: 20px; }
.p-20 { padding: 20px; }

/* Responsive */
@media (max-width: 768px) {
    .container { padding: 20px; }
    h1 { font-size: 28px; }
    .input-group { flex-direction: column; }
    button { width: 100%; }
}
EOF

print_success "Public files created"

# ============================================
# HELPER FILES
# ============================================
print_header "Creating helper files"

cat > app/Helpers/functions.php << 'EOF'
<?php

if (!function_exists('dd')) {
    function dd(...$vars)
    {
        foreach ($vars as $var) {
            echo '<pre>';
            var_dump($var);
            echo '</pre>';
        }
        die();
    }
}

if (!function_exists('env')) {
    function env($key, $default = null)
    {
        $value = getenv($key);
        if ($value === false) {
            return $default;
        }
        return $value;
    }
}

if (!function_exists('redirect')) {
    function redirect($url, $statusCode = 302)
    {
        header("Location: $url", true, $statusCode);
        exit;
    }
}

if (!function_exists('jsonResponse')) {
    function jsonResponse($data, $statusCode = 200)
    {
        http_response_code($statusCode);
        header('Content-Type: application/json');
        echo json_encode($data);
        exit;
    }
}

if (!function_exists('generateQrCode')) {
    function generateQrCode($url)
    {
        return "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" . urlencode($url);
    }
}

if (!function_exists('getClientIp')) {
    function getClientIp()
    {
        $ip = null;
        
        if (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        
        return $ip;
    }
}

if (!function_exists('isValidUrl')) {
    function isValidUrl($url)
    {
        return filter_var($url, FILTER_VALIDATE_URL) !== false;
    }
}
EOF

cat > app/Helpers/SecurityHelper.php << 'EOF'
<?php

namespace App\Helpers;

class SecurityHelper
{
    public static function sanitizeInput($input)
    {
        if (is_array($input)) {
            return array_map([self::class, 'sanitizeInput'], $input);
        }
        
        return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
    }
    
    public static function generateCsrfToken()
    {
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }
    
    public static function verifyCsrfToken($token)
    {
        return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
    }
    
    public static function generateRandomString($length = 32)
    {
        return bin2hex(random_bytes($length / 2));
    }
    
    public static function hashPassword($password)
    {
        return password_hash($password, PASSWORD_DEFAULT);
    }
    
    public static function verifyPassword($password, $hash)
    {
        return password_verify($password, $hash);
    }
}
EOF

print_success "Helper files created"

# ============================================
# CREATE INSTALL SCRIPT
# ============================================
cat > install.sh << 'EOF'
#!/bin/bash

echo "========================================="
echo "   PolaSaja URL Shortener Installation"
echo "========================================="
echo ""

# Check PHP version
PHP_VERSION=$(php -v | head -n 1 | cut -d " " -f 2 | cut -d "." -f 1,2)
echo "✓ PHP Version: $PHP_VERSION"

# Check MySQL
if command -v mysql &> /dev/null; then
    echo "✓ MySQL found"
else
    echo "✗ MySQL not found. Please install MySQL first."
    exit 1
fi

# Load .env
if [ -f .env ]; then
    source .env
fi

# Create database
echo ""
echo "📊 Setting up database..."

read -p "Enter MySQL root password: " MYSQL_PASS

mysql -u root -p$MYSQL_PASS -e "CREATE DATABASE IF NOT EXISTS $DB_DATABASE"
mysql -u root -p$MYSQL_PASS -e "CREATE USER IF NOT EXISTS '$DB_USERNAME'@'localhost' IDENTIFIED BY '$DB_PASSWORD'"
mysql -u root -p$MYSQL_PASS -e "GRANT ALL PRIVILEGES ON $DB_DATABASE.* TO '$DB_USERNAME'@'localhost'"
mysql -u root -p$MYSQL_PASS -e "FLUSH PRIVILEGES"

echo "✓ Database created"

# Run migrations
echo ""
echo "📦 Running migrations..."

for file in database/migrations/*.php; do
    echo "  Running: $(basename $file)"
    php -r "
        \$config = require '$file';
        \$db = new PDO('mysql:host=$DB_HOST;dbname=$DB_DATABASE;charset=utf8mb4', '$DB_USERNAME', '$DB_PASSWORD');
        \$db->exec(\$config['up']);
    "
done

echo "✓ Migrations completed"

# Create admin user
echo ""
echo "👤 Creating admin user..."

php -r "
\$db = new PDO('mysql:host=$DB_HOST;dbname=$DB_DATABASE;charset=utf8mb4', '$DB_USERNAME', '$DB_PASSWORD');
\$password = password_hash('Admin123!', PASSWORD_DEFAULT);
\$apiKey = bin2hex(random_bytes(32));

\$stmt = \$db->prepare(\"
    INSERT INTO users (name, email, password, role, api_key, email_verified, is_active)
    VALUES ('Administrator', '$ADMIN_EMAIL', :password, 'admin', :api_key, 1, 1)
    ON DUPLICATE KEY UPDATE id=id
\");
\$stmt->execute([':password' => \$password, ':api_key' => \$apiKey]);

echo \"Admin user created\\n\";
echo \"Email: $ADMIN_EMAIL\\n\";
echo \"Password: Admin123!\\n\";
"

echo ""
echo "========================================="
echo "   INSTALLATION COMPLETE!"
echo "========================================="
echo ""
echo "🌐 Start the server:"
echo "   cd public && php -S localhost:8000"
echo ""
echo "📱 Access the application:"
echo "   http://id.polasaja.com"
echo ""
echo "👤 Admin Login:"
echo "   Email: $ADMIN_EMAIL"
echo "   Password: Admin123!"
echo ""
EOF

chmod +x install.sh

# ============================================
# FINAL OUTPUT
# ============================================
echo ""
echo "========================================="
print_success "URL SHORTENER INSTALLATION COMPLETE!"
echo "========================================="
echo ""
echo "📁 Project created at: $(pwd)"
echo ""
echo "📋 Next steps:"
echo ""
echo "1. Edit database configuration:"
echo "   nano .env"
echo ""
echo "2. Run database installation:"
echo "   ./install.sh"
echo ""
echo "3. Start the server:"
echo "   cd public && php -S localhost:8000"
echo ""
echo "4. Or configure Apache/Nginx to point to public/ directory"
echo ""
echo "🌐 Your URL shortener will be available at:"
echo "   http://id.polasaja.com"
echo ""
echo "📚 API Endpoints:"
echo "   POST   /api/shorten     - Create short URL"
echo "   GET    /api/stats       - Get global statistics"
echo "   GET    /api/stats/{code} - Get URL statistics"
echo "   GET    /api/info/{code}  - Get URL information"
echo ""
