import os

files = {}

files["app/Config/Settings.php"] = """<?php
namespace App\Config;

class Settings {
    public static function get($key, $default = null) {
        global $db;
        $stmt = $db->prepare("SELECT setting_value FROM settings WHERE setting_key = ?");
        $stmt->execute([$key]);
        $row = $stmt->fetch();
        return $row ? $row['setting_value'] : $default;
    }

    public static function set($key, $value) {
        global $db;
        $stmt = $db->prepare("INSERT INTO settings (setting_key, setting_value, updated_at) VALUES (?, ?, NOW()) ON DUPLICATE KEY UPDATE setting_value = ?, updated_at = NOW()");
        $stmt->execute([$key, $value, $value]);
    }
}
"""

files["app/Database/DB.php"] = """<?php
namespace App\Database;

use PDO;
use PDOException;

class DB {
    private static $instance = null;

    public static function getInstance() {
        if (self::$instance === null) {
            $host = getenv('DB_HOST') ?: '127.0.0.1';
            $db   = getenv('DB_NAME');
            $user = getenv('DB_USER');
            $pass = getenv('DB_PASS');
            $charset = 'utf8mb4';

            $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
            $options = [
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES   => false,
            ];

            try {
                self::$instance = new PDO($dsn, $user, $pass, $options);
            } catch (PDOException $e) {
                die("Database connection failed. Please check your configuration.");
            }
        }
        return self::$instance;
    }
}
"""

files["app/Models/User.php"] = """<?php
namespace App\Models;

class User {
    public static function getAdminByUsername($username) {
        global $db;
        $stmt = $db->prepare("SELECT * FROM users WHERE username = ? AND role = 'admin' AND status = 'active' LIMIT 1");
        $stmt->execute([$username]);
        return $stmt->fetch();
    }
}
"""

files["app/Models/Group.php"] = """<?php
namespace App\Models;

class Group {
    public static function create($telegram_group_id, $telegram_access_hash, $group_name, $group_type, $invite_link, $image_status, $image_path, $status, $created_by) {
        global $db;
        $stmt = $db->prepare("INSERT INTO telegram_groups (telegram_group_id, telegram_access_hash, group_name, group_type, invite_link, image_status, image_path, status, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())");
        $stmt->execute([$telegram_group_id, $telegram_access_hash, $group_name, $group_type, $invite_link, $image_status, $image_path, $status, $created_by]);
        return $db->lastInsertId();
    }

    public static function update($id, $data) {
        global $db;
        $fields = [];
        $values = [];
        foreach ($data as $key => $val) {
            $fields[] = "$key = ?";
            $values[] = $val;
        }
        $values[] = $id;
        $stmt = $db->prepare("UPDATE telegram_groups SET " . implode(', ', $fields) . ", updated_at = NOW() WHERE id = ?");
        return $stmt->execute($values);
    }
    
    public static function getById($id) {
        global $db;
        $stmt = $db->prepare("SELECT * FROM telegram_groups WHERE id = ?");
        $stmt->execute([$id]);
        return $stmt->fetch();
    }
}
"""

files["app/Models/AutoAdmin.php"] = """<?php
namespace App\Models;

class AutoAdmin {
    public static function getAllActive() {
        global $db;
        $stmt = $db->query("SELECT * FROM auto_admins WHERE status = 'active'");
        return $stmt->fetchAll();
    }
}
"""

files["app/Models/GroupAdmin.php"] = """<?php
namespace App\Models;

class GroupAdmin {
    public static function add($group_id, $telegram_user_id, $add_status, $promotion_status, $error_message = null) {
        global $db;
        $stmt = $db->prepare("INSERT INTO group_admins (group_id, telegram_user_id, add_status, promotion_status, error_message, created_at, updated_at) VALUES (?, ?, ?, ?, ?, NOW(), NOW())");
        return $stmt->execute([$group_id, $telegram_user_id, $add_status, $promotion_status, $error_message]);
    }
}
"""

files["app/Models/Log.php"] = """<?php
namespace App\Models;

class Log {
    public static function add($telegram_user_id, $group_id, $action, $status, $message, $error_message = null) {
        global $db;
        $stmt = $db->prepare("INSERT INTO bot_logs (telegram_user_id, group_id, action, status, message, error_message, created_at) VALUES (?, ?, ?, ?, ?, ?, NOW())");
        $stmt->execute([$telegram_user_id, $group_id, $action, $status, $message, $error_message]);
    }
}
"""

files["app/Models/Job.php"] = """<?php
namespace App\Models;

class Job {
    public static function push($type, $payload, $delay_seconds = 0) {
        global $db;
        $stmt = $db->prepare("INSERT INTO jobs (job_type, payload, status, available_at, created_at, updated_at) VALUES (?, ?, 'pending', DATE_ADD(NOW(), INTERVAL ? SECOND), NOW(), NOW())");
        return $stmt->execute([$type, json_encode($payload), $delay_seconds]);
    }
}
"""

files["app/Services/TelegramBotService.php"] = """<?php
namespace App\Services;

class TelegramBotService {
    private $token;
    
    public function __construct() {
        $this->token = getenv('TELEGRAM_BOT_TOKEN');
    }

    public function sendMessage($chat_id, $text, $parse_mode = 'HTML', $reply_markup = null) {
        $url = "https://api.telegram.org/bot" . $this->token . "/sendMessage";
        $data = [
            'chat_id' => $chat_id,
            'text' => $text,
            'parse_mode' => $parse_mode
        ];
        if ($reply_markup) {
            $data['reply_markup'] = json_encode($reply_markup);
        }
        return $this->request($url, $data);
    }
    
    public function editMessageText($chat_id, $message_id, $text, $parse_mode = 'HTML', $reply_markup = null) {
        $url = "https://api.telegram.org/bot" . $this->token . "/editMessageText";
        $data = [
            'chat_id' => $chat_id,
            'message_id' => $message_id,
            'text' => $text,
            'parse_mode' => $parse_mode
        ];
        if ($reply_markup) {
            $data['reply_markup'] = json_encode($reply_markup);
        }
        return $this->request($url, $data);
    }

    private function request($url, $data) {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $response = curl_exec($ch);
        curl_close($ch);
        return json_decode($response, true);
    }
}
"""

files["app/Services/MTProtoService.php"] = """<?php
namespace App\Services;

use danog\MadelineProto\\API;
use danog\MadelineProto\\Settings;

class MTProtoService {
    private $MadelineProto;

    public function __construct() {
        $sessionPath = __DIR__ . '/../../storage/sessions/mtproto.session';
        $settings = new Settings;
        
        $apiId = getenv('TELEGRAM_API_ID');
        $apiHash = getenv('TELEGRAM_API_HASH');
        
        if ($apiId && $apiHash) {
            $appInfo = new Settings\\AppInfo;
            $appInfo->setApiId((int)$apiId)->setApiHash($apiHash);
            $settings->setAppInfo($appInfo);
        }
        
        $this->MadelineProto = new API($sessionPath, $settings);
    }

    public function getAPI() {
        return $this->MadelineProto;
    }

    public function createPrivateGroup($title) {
        try {
            $updates = $this->MadelineProto->messages->createChat([
                'users' => ['@me'], // Create with self initially
                'title' => $title
            ]);
            
            $chatId = null;
            foreach ($updates['chats'] as $chat) {
                if ($chat['title'] === $title) {
                    $chatId = $chat['id'];
                    break;
                }
            }
            if (!$chatId) {
                throw new \\Exception("Failed to find created chat ID");
            }
            return ['success' => true, 'chat_id' => '-'.$chatId];
        } catch (\\Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
    
    public function convertToSupergroup($chatId) {
        try {
            $result = $this->MadelineProto->messages->migrateChat(['chat_id' => abs($chatId)]);
            $channelId = null;
            $accessHash = null;
            foreach ($result['chats'] as $chat) {
                if (isset($chat['_']) && $chat['_'] === 'channel') {
                    $channelId = '-100' . $chat['id'];
                    $accessHash = $chat['access_hash'];
                    break;
                }
            }
            return ['success' => true, 'channel_id' => $channelId, 'access_hash' => $accessHash];
        } catch (\\Exception $e) {
             return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    public function generateInviteLink($peer) {
        try {
            $result = $this->MadelineProto->messages->exportChatInvite([
                'peer' => $peer,
            ]);
            return ['success' => true, 'link' => $result['link']];
        } catch (\\Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    public function setGroupPhoto($peer, $imagePath) {
        try {
            $result = $this->MadelineProto->messages->editChatPhoto([
                'chat_id' => abs($peer),
                'photo' => $this->MadelineProto->messages->uploadMedia([
                    'media' => [
                        '_' => 'inputMediaUploadedPhoto',
                        'file' => $imagePath
                    ]
                ])
            ]);
            return ['success' => true];
        } catch (\\Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    public function setChannelPhoto($peer, $imagePath) {
         try {
             $result = $this->MadelineProto->channels->editPhoto([
                 'channel' => $peer,
                 'photo' => [
                     '_' => 'inputChatUploadedPhoto',
                     'file' => $imagePath
                 ]
             ]);
             return ['success' => true];
         } catch (\\Exception $e) {
             return ['success' => false, 'error' => $e->getMessage()];
         }
    }

    public function addAdmin($peer, $userId) {
        try {
            // First add user
            $this->MadelineProto->channels->inviteToChannel([
                'channel' => $peer,
                'users' => [$userId]
            ]);
            
            // Then promote
            $this->MadelineProto->channels->editAdmin([
                'channel' => $peer,
                'user_id' => $userId,
                'admin_rights' => [
                    '_' => 'chatAdminRights',
                    'change_info' => true,
                    'post_messages' => true,
                    'edit_messages' => true,
                    'delete_messages' => true,
                    'ban_users' => true,
                    'invite_users' => true,
                    'pin_messages' => true,
                    'add_admins' => true,
                    'anonymous' => false,
                    'manage_call' => true,
                    'other' => true,
                    'manage_topics' => true,
                ],
                'rank' => 'Admin'
            ]);
            
            return ['success' => true];
        } catch (\\Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}
"""

files["app/Services/QueueService.php"] = """<?php
namespace App\Services;

class QueueService {
    public function processNext() {
        global $db;
        $db->beginTransaction();
        
        $stmt = $db->query("SELECT * FROM jobs WHERE status = 'pending' AND available_at <= NOW() ORDER BY id ASC LIMIT 1 FOR UPDATE SKIP LOCKED");
        $job = $stmt->fetch();
        
        if (!$job) {
            $db->rollBack();
            return false;
        }
        
        $db->prepare("UPDATE jobs SET status = 'processing', locked_at = NOW(), attempts = attempts + 1 WHERE id = ?")->execute([$job['id']]);
        $db->commit();
        
        return $job;
    }
    
    public function markCompleted($jobId) {
        global $db;
        $db->prepare("UPDATE jobs SET status = 'completed', completed_at = NOW() WHERE id = ?")->execute([$jobId]);
    }
    
    public function markFailed($jobId, $error, $maxAttempts = 3) {
        global $db;
        $stmt = $db->prepare("SELECT attempts FROM jobs WHERE id = ?");
        $stmt->execute([$jobId]);
        $job = $stmt->fetch();
        
        if ($job['attempts'] >= $maxAttempts) {
            $db->prepare("UPDATE jobs SET status = 'failed', error_message = ? WHERE id = ?")->execute([$error, $jobId]);
        } else {
            $delay = pow(2, $job['attempts']) * 60; // exponential backoff
            $db->prepare("UPDATE jobs SET status = 'pending', available_at = DATE_ADD(NOW(), INTERVAL ? SECOND), error_message = ? WHERE id = ?")->execute([$delay, $error, $jobId]);
        }
    }
}
"""

files["app/bootstrap.php"] = """<?php
require_once __DIR__ . '/../vendor/autoload.php';

// Load .env
if (file_exists(__DIR__ . '/../.env')) {
    $lines = file(__DIR__ . '/../.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        if (strpos(trim($line), '#') === 0) continue;
        list($name, $value) = explode('=', $line, 2);
        putenv(trim($name) . '=' . trim($value));
    }
}

// Init DB
global $db;
$db = \App\Database\DB::getInstance();

date_default_timezone_set(getenv('APP_TIMEZONE') ?: 'UTC');
"""

for path, content in files.items():
    os.makedirs(os.path.dirname(path), exist_ok=True)
    with open(path, "w", encoding="utf-8") as f:
        f.write(content)

print("Core files generated successfully.")
