<?php
// engine.php
// Unified backend: parser, builder, organiser, EPG, editor

session_start();

$DB_FILE = __DIR__ . '/iptv.json';

// ---------- DB helpers ----------

function load_db($file) {
    if (!file_exists($file)) {
        return [
            'stats' => [
                'created' => date('c'),
                'updated' => date('c'),
                'channels' => 0,
                'epg_sources' => 0
            ],
            'channels' => [],
            'epg' => [] // channelId => [programs]
        ];
    }
    $data = json_decode(file_get_contents($file), true);
    if (!$data) {
        $data = [
            'stats' => [
                'created' => date('c'),
                'updated' => date('c'),
                'channels' => 0,
                'epg_sources' => 0
            ],
            'channels' => [],
            'epg' => []
        ];
    }
    $data['channels'] = $data['channels'] ?? [];
    $data['epg'] = $data['epg'] ?? [];
    $data['stats'] = $data['stats'] ?? [
        'created' => date('c'),
        'updated' => date('c'),
        'channels' => count($data['channels']),
        'epg_sources' => 0
    ];
    return $data;
}

function save_db($file, $db) {
    $db['stats']['updated'] = date('c');
    $db['stats']['channels'] = count($db['channels']);
    file_put_contents($file, json_encode($db, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}

// ---------- Normalisation helpers (Option C) ----------

function slugify($str) {
    $str = strtolower(trim($str));
    $str = preg_replace('/[^a-z0-9]+/', '-', $str);
    $str = preg_replace('/-+/', '-', $str);
    return trim($str, '-');
}

function detect_country_from_name($name) {
    $name = strtoupper($name);
    if (strpos($name, 'NZ-') === 0) return 'NZ';
    if (strpos($name, 'UK-') === 0) return 'UK';
    if (strpos($name, 'US-') === 0) return 'US';
    return null;
}

function detect_country($url, $filename = '', $name = '') {
    $fromName = detect_country_from_name($name);
    if ($fromName) return $fromName;

    $hay = strtolower($url . ' ' . $filename);
    if (strpos($hay, '.nz') !== false || strpos($hay, 'mjh.nz') !== false) return 'NZ';
    if (strpos($hay, '.co.uk') !== false || strpos($hay, 'uk-') !== false) return 'UK';
    if (strpos($hay, '.us') !== false || strpos($hay, 'pluto') !== false || strpos($hay, 'tubi') !== false) return 'US';
    return 'XX';
}

function generate_id($name, $country, $network = '') {
    $slug = slugify($name);
    $prefix = strtolower($country);
    if ($network) {
        $netSlug = slugify($network);
        return $prefix . '-' . $netSlug . '-' . $slug;
    }
    return $prefix . '-' . $slug;
}

function generate_logo($id, $country) {
    $c = strtolower($country);
    $slug = preg_replace('/^[a-z]{2}-/', '', $id);
    return "https://iptv-org.github.io/iptv/logos/$c/$slug.png";
}

function guess_category($name, $tags = []) {
    $hay = strtolower($name . ' ' . implode(' ', $tags));
    if (strpos($hay, 'sport') !== false) return 'Sports';
    if (strpos($hay, 'news') !== false) return 'News';
    if (strpos($hay, 'kids') !== false || strpos($hay, 'cartoon') !== false) return 'Kids';
    if (strpos($hay, 'movie') !== false || strpos($hay, 'film') !== false) return 'Movies';
    return 'TV';
}

function normalize_channel($raw, $filename = '') {
    $name = $raw['name'] ?? $raw['title'] ?? '';
    $url  = $raw['url'] ?? $raw['location'] ?? '';
    if (!$url) return null;

    $network = $raw['network'] ?? $filename;
    $country = $raw['country'] ?? detect_country($url, $filename, $name);
    $tags = $raw['tags'] ?? [];
    $category = $raw['category'] ?? guess_category($name, $tags);

    $id = $raw['id'] ?? generate_id($name ?: $url, $country, $network);
    $slug = $raw['slug'] ?? slugify($name ?: $url);
    $logo = $raw['logo'] ?? $raw['thumb'] ?? generate_logo($id, $country);
    $isLive = isset($raw['isLive']) ? (bool)$raw['isLive'] : true;
    $description = $raw['description'] ?? '';

    return [
        'id'          => $id,
        'name'        => $name ?: $url,
        'slug'        => $slug,
        'url'         => $url,
        'logo'        => $logo,
        'country'     => $country,
        'category'    => $category,
        'tags'        => $tags,
        'isLive'      => $isLive,
        'network'     => $network,
        'description' => $description
    ];
}

function sort_channels(&$channels) {
    usort($channels, function($a, $b) {
        $ca = $a['category'] ?? '';
        $cb = $b['category'] ?? '';
        if ($ca === $cb) {
            return strcasecmp($a['name'], $b['name']);
        }
        return strcasecmp($ca, $cb);
    });
}

// ---------- Parsers ----------

function parse_m3u($content, $filename = '') {
    $lines = preg_split('/\r\n|\r|\n/', $content);
    $channels = [];
    $meta = null;

    foreach ($lines as $line) {
        $line = trim($line);
        if ($line === '' || strpos($line, '#EXTM3U') === 0) continue;

        if (strpos($line, '#EXTINF:') === 0) {
            $meta = [
                'name' => '',
                'url'  => '',
                'logo' => null,
                'group'=> null,
                'id'   => null
            ];
            $after = substr($line, 8);
            $parts = explode(',', $after, 2);
            $attrs = $parts[0] ?? '';
            $name  = $parts[1] ?? '';
            $meta['name'] = trim($name);

            if (preg_match_all('/(\w+?)="(.*?)"/', $attrs, $m, PREG_SET_ORDER)) {
                foreach ($m as $match) {
                    $key = strtolower($match[1]);
                    $val = $match[2];
                    if ($key === 'tvg-id') $meta['id'] = $val;
                    elseif ($key === 'tvg-logo') $meta['logo'] = $val;
                    elseif ($key === 'group-title') $meta['group'] = $val;
                }
            }
        } elseif ($line[0] !== '#') {
            if ($meta) {
                $meta['url'] = $line;
                $channels[] = normalize_channel([
                    'id'       => $meta['id'],
                    'name'     => $meta['name'],
                    'url'      => $meta['url'],
                    'logo'     => $meta['logo'],
                    'category' => $meta['group']
                ], $filename);
                $meta = null;
            } else {
                $channels[] = normalize_channel([
                    'name' => $line,
                    'url'  => $line
                ], $filename);
            }
        }
    }
    return array_values(array_filter($channels));
}

function parse_json_content($content, $filename = '') {
    $data = json_decode($content, true);
    $out = [];

    if (!$data) return $out;

    // Option C format
    if (isset($data['channels']) && is_array($data['channels'])) {
        foreach ($data['channels'] as $ch) {
            $norm = normalize_channel($ch, $filename);
            if ($norm) $out[] = $norm;
        }
    }
    // items[] format
    elseif (isset($data['items']) && is_array($data['items'])) {
        $group = $data['category'] ?? null;
        foreach ($data['items'] as $item) {
            $item['category'] = $item['category'] ?? $group;
            $norm = normalize_channel($item, $filename);
            if ($norm) $out[] = $norm;
        }
    }
    // array of channels
    elseif (isset($data[0]) && is_array($data[0])) {
        foreach ($data as $item) {
            $norm = normalize_channel($item, $filename);
            if ($norm) $out[] = $norm;
        }
    }

    return $out;
}

// Very simple XMLTV parser (XMLTV → EPG)
function parse_xmltv($xmlContent) {
    $epg = []; // channelId => programs[]
    libxml_use_internal_errors(true);
    $xml = simplexml_load_string($xmlContent);
    if (!$xml) return $epg;

    // Map XMLTV channel id → display-name
    $channelNames = [];
    foreach ($xml->channel as $ch) {
        $id = (string)$ch['id'];
        $name = (string)$ch->{'display-name'};
        $channelNames[$id] = $name;
    }

    foreach ($xml->programme as $p) {
        $cid = (string)$p['channel'];
        $start = (string)$p['start'];
        $stop  = (string)$p['stop'];
        $title = (string)$p->title;
        $desc  = (string)$p->desc;

        if (!isset($epg[$cid])) $epg[$cid] = [];
        $epg[$cid][] = [
            'title' => $title,
            'start' => $start,
            'stop'  => $stop,
            'desc'  => $desc
        ];
    }
    return $epg;
}

// ---------- Export helpers ----------

function export_m3u($channels) {
    $lines = ["#EXTM3U"];
    foreach ($channels as $ch) {
        $attrs = [];
        if (!empty($ch['id']))    $attrs[] = 'tvg-id="' . addslashes($ch['id']) . '"';
        if (!empty($ch['logo']))  $attrs[] = 'tvg-logo="' . addslashes($ch['logo']) . '"';
        if (!empty($ch['category'])) $attrs[] = 'group-title="' . addslashes($ch['category']) . '"';
        $name = $ch['name'] ?? $ch['url'];
        $lines[] = '#EXTINF:-1 ' . implode(' ', $attrs) . ',' . $name;
        $lines[] = $ch['url'];
    }
    return implode("\n", $lines);
}

function export_csv($channels) {
    $fh = fopen('php://temp', 'r+');
    fputcsv($fh, ['id','name','slug','url','logo','country','category','tags','isLive','network','description']);
    foreach ($channels as $ch) {
        fputcsv($fh, [
            $ch['id'] ?? '',
            $ch['name'] ?? '',
            $ch['slug'] ?? '',
            $ch['url'] ?? '',
            $ch['logo'] ?? '',
            $ch['country'] ?? '',
            $ch['category'] ?? '',
            implode('|', $ch['tags'] ?? []),
            !empty($ch['isLive']) ? 1 : 0,
            $ch['network'] ?? '',
            $ch['description'] ?? ''
        ]);
    }
    rewind($fh);
    return stream_get_contents($fh);
}

function export_sql($channels, $table = 'iptv_channels') {
    $lines = [];
    $lines[] = "CREATE TABLE IF NOT EXISTS `$table` (";
    $lines[] = "  id VARCHAR(255) PRIMARY KEY,";
    $lines[] = "  name VARCHAR(255),";
    $lines[] = "  slug VARCHAR(255),";
    $lines[] = "  url TEXT,";
    $lines[] = "  logo TEXT,";
    $lines[] = "  country VARCHAR(8),";
    $lines[] = "  category VARCHAR(64),";
    $lines[] = "  tags TEXT,";
    $lines[] = "  isLive TINYINT(1),";
    $lines[] = "  network VARCHAR(255),";
    $lines[] = "  description TEXT";
    $lines[] = ");";
    $lines[] = "";

    foreach ($channels as $ch) {
        $vals = [
            'id'          => $ch['id'] ?? '',
            'name'        => $ch['name'] ?? '',
            'slug'        => $ch['slug'] ?? '',
            'url'         => $ch['url'] ?? '',
            'logo'        => $ch['logo'] ?? '',
            'country'     => $ch['country'] ?? '',
            'category'    => $ch['category'] ?? '',
            'tags'        => implode('|', $ch['tags'] ?? []),
            'isLive'      => !empty($ch['isLive']) ? 1 : 0,
            'network'     => $ch['network'] ?? '',
            'description' => $ch['description'] ?? ''
        ];
        $escaped = array_map(function($v) {
            return "'" . str_replace("'", "''", $v) . "'";
        }, $vals);
        $lines[] = "INSERT INTO `$table` (`id`,`name`,`slug`,`url`,`logo`,`country`,`category`,`tags`,`isLive`,`network`,`description`) VALUES (" . implode(',', $escaped) . ");";
    }
    return implode("\n", $lines);
}

// ---------- Simple dead-check (optional) ----------

function check_dead_stream($url, $timeout = 3) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_NOBODY => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => $timeout,
        CURLOPT_FOLLOWLOCATION => true
    ]);
    curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    return ($code < 200 || $code >= 400);
}

// ---------- API router ----------

if (isset($_GET['action'])) {
    header('Content-Type: application/json; charset=utf-8');
    $action = $_GET['action'];
    $db = load_db($DB_FILE);

    // List channels (with optional search)
    if ($action === 'list') {
        $q = isset($_GET['q']) ? trim($_GET['q']) : '';
        $channels = $db['channels'];
        sort_channels($channels);
        if ($q !== '') {
            $qLower = mb_strtolower($q);
            $channels = array_values(array_filter($channels, function($ch) use ($qLower) {
                $hay = mb_strtolower(($ch['name'] ?? '') . ' ' . ($ch['description'] ?? '') . ' ' . implode(' ', $ch['tags'] ?? []));
                return strpos($hay, $qLower) !== false;
            }));
        }
        echo json_encode(['stats' => $db['stats'], 'channels' => $channels]);
        exit;
    }

    // Upload files (M3U / JSON / XMLTV)
    if ($action === 'upload' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $newChannels = [];
        $newEpg = [];
        if (isset($_FILES['files'])) {
            $files = $_FILES['files'];
            for ($i = 0; $i < count($files['name']); $i++) {
                if ($files['error'][$i] !== UPLOAD_ERR_OK) continue;
                $name = $files['name'][$i];
                $ext  = strtolower(pathinfo($name, PATHINFO_EXTENSION));
                $content = file_get_contents($files['tmp_name'][$i]);

                if (in_array($ext, ['m3u','m3u8'])) {
                    $parsed = parse_m3u($content, $name);
                    $newChannels = array_merge($newChannels, $parsed);
                } elseif ($ext === 'json') {
                    $parsed = parse_json_content($content, $name);
                    $newChannels = array_merge($newChannels, $parsed);
                } elseif (in_array($ext, ['xml','xmltv'])) {
                    $epg = parse_xmltv($content);
                    $newEpg = array_merge_recursive($newEpg, $epg);
                }
            }
        }

        // Merge channels (dedupe by URL)
        $all = array_merge($db['channels'], $newChannels);
        $seen = [];
        $merged = [];
        foreach ($all as $ch) {
            if (empty($ch['url'])) continue;
            $key = $ch['url'];
            if (isset($seen[$key])) continue;
            $seen[$key] = true;
            $merged[] = $ch;
        }
        $db['channels'] = $merged;

        // Merge EPG (keyed by XMLTV channel id; mapping to our ids is up to you)
        foreach ($newEpg as $cid => $programs) {
            if (!isset($db['epg'][$cid])) $db['epg'][$cid] = [];
            $db['epg'][$cid] = array_merge($db['epg'][$cid], $programs);
        }
        $db['stats']['epg_sources'] = count($db['epg']);

        save_db($DB_FILE, $db);
        echo json_encode(['status' => 'ok', 'added_channels' => count($newChannels), 'epg_sources' => count($newEpg)]);
        exit;
    }

    // Ingest by URL (M3U / JSON / XMLTV)
    if ($action === 'ingest_url' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $body = json_decode(file_get_contents('php://input'), true);
        $url = $body['url'] ?? '';
        if (!$url) {
            echo json_encode(['error' => 'No URL']);
            exit;
        }
        $content = @file_get_contents($url);
        if ($content === false) {
            echo json_encode(['error' => 'Unable to fetch URL']);
            exit;
        }
        $ext = strtolower(pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
        $newChannels = [];
        $newEpg = [];

        if (in_array($ext, ['m3u','m3u8'])) {
            $newChannels = parse_m3u($content, basename($url));
        } elseif ($ext === 'json') {
            $newChannels = parse_json_content($content, basename($url));
        } elseif (in_array($ext, ['xml','xmltv'])) {
            $newEpg = parse_xmltv($content);
        }

        $all = array_merge($db['channels'], $newChannels);
        $seen = [];
        $merged = [];
        foreach ($all as $ch) {
            if (empty($ch['url'])) continue;
            $key = $ch['url'];
            if (isset($seen[$key])) continue;
            $seen[$key] = true;
            $merged[] = $ch;
        }
        $db['channels'] = $merged;

        foreach ($newEpg as $cid => $programs) {
            if (!isset($db['epg'][$cid])) $db['epg'][$cid] = [];
            $db['epg'][$cid] = array_merge($db['epg'][$cid], $programs);
        }
        $db['stats']['epg_sources'] = count($db['epg']);

        save_db($DB_FILE, $db);
        echo json_encode(['status' => 'ok', 'added_channels' => count($newChannels), 'epg_sources' => count($newEpg)]);
        exit;
    }

    // Save edited channels
    if ($action === 'save' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $raw = json_decode(file_get_contents('php://input'), true);
        $channels = $raw['channels'] ?? [];
        $db['channels'] = $channels;
        save_db($DB_FILE, $db);
        echo json_encode(['status' => 'ok', 'count' => count($channels)]);
        exit;
    }

    // Export
    if ($action === 'export') {
        $type = $_GET['type'] ?? 'json';
        $channels = $db['channels'];
        sort_channels($channels);

        if ($type === 'm3u') {
            echo json_encode(['type' => 'm3u', 'content' => export_m3u($channels)]);
        } elseif ($type === 'csv') {
            echo json_encode(['type' => 'csv', 'content' => export_csv($channels)]);
        } elseif ($type === 'sql') {
            echo json_encode(['type' => 'sql', 'content' => export_sql($channels)]);
        } else {
            echo json_encode(['type' => 'json', 'content' => json_encode(['channels' => $channels], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)]);
        }
        exit;
    }

    // Check dead streams (first N)
    if ($action === 'check_dead' && $_SERVER['REQUEST_METHOD'] === 'POST') {
        $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 50;
        $checked = 0;
        $dead = [];
        foreach ($db['channels'] as $idx => $ch) {
            if ($checked >= $limit) break;
            $url = $ch['url'] ?? '';
            if (!$url) continue;
            $isDead = check_dead_stream($url);
            $db['channels'][$idx]['dead'] = $isDead;
            if ($isDead) $dead[] = $ch['id'] ?? $url;
            $checked++;
        }
        save_db($DB_FILE, $db);
        echo json_encode(['checked' => $checked, 'dead' => $dead]);
        exit;
    }

    // Get EPG for a channel (by id or xmltv id)
    if ($action === 'epg') {
        $cid = $_GET['channel'] ?? '';
        $epg = $db['epg'][$cid] ?? [];
        echo json_encode(['channel' => $cid, 'programs' => $epg]);
        exit;
    }

    echo json_encode(['error' => 'Unknown action']);
    exit;
}