<?php

namespace Cron;

use Entity\Kampagne;

class AdCityForcedTextlinkCron extends AbstractCron
{
    private const API_URL = 'https://www.adcity.eu/interface/';
    private const KAMPAGNE_TYPE = 'forcedtextlink';
    private const LOGIN_URL = 'https://www.adcity.eu/';
    private const INTERFACE_URL = 'https://www.adcity.eu/index.php?seite=content/member/interface';
    private const USERNAME = 'Greggy';
    private const PASSWORD = 'zOP2458E';

    private string $cookieFile;

    /**
     * Gibt den Username des Werbenetzwerk-Users zurück
     */
    protected function getWerbenetzwerkUsername(): string
    {
        return 'adcity-eu';
    }

    /**
     * Konstruktor
     */
    public function __construct($entityManager)
    {
        parent::__construct($entityManager);
        $this->cookieFile = sys_get_temp_dir() . '/adcity_cookies.txt';
    }

    /**
     * Führt den Cron-Job aus
     */
    public function run(): void
    {
        $this->log("Starting AdCity ForcedTextlink Cron...");

        // Werbenetzwerk-Daten laden
        $this->loadWerbenetzwerkData();

        // Umrechnungskurs aktualisieren
        $this->updateUmrechnungskurs();

        // ForcedTextlink Kampagnen abrufen
        $this->log("=== Fetching ForcedTextlink campaigns ===");
        $statsForcedTextlink = $this->fetchAndProcessKampagnen('forcedtextlink', 'is_ft');

        // Paidmail Kampagnen abrufen
        $this->log("\n=== Fetching Paidmail campaigns ===");
        $statsPaidmail = $this->fetchAndProcessKampagnen('paidmail', 'is_mail');

        // Traffic Kampagnen abrufen
        $this->log("\n=== Fetching Traffic campaigns ===");
        $statsTraffic = $this->fetchAndProcessKampagnen('traffic', 'is_tr');

        // Änderungen speichern
        $this->flush();

        // Zusammenfassung ausgeben
        $this->log("\n=== Overall Summary ===");
        $totalStats = [
            'total' => $statsForcedTextlink['total'] + $statsPaidmail['total'] + $statsTraffic['total'],
            'created' => $statsForcedTextlink['created'] + $statsPaidmail['created'] + $statsTraffic['created'],
            'updated' => $statsForcedTextlink['updated'] + $statsPaidmail['updated'] + $statsTraffic['updated']
        ];
        $this->printSummary($totalStats['total'], $totalStats['created'], $totalStats['updated']);
        $this->log("Cron job completed successfully.");
    }

    /**
     * Ruft Kampagnen von der API ab und verarbeitet sie
     */
    private function fetchAndProcessKampagnen(string $type, string $kampagneType): array
    {
        // API-Anfrage durchführen
        $response = $this->fetchFromApi(self::API_URL, [
            'typ' => $type,
            'id' => $this->werbenetzwerk->getUserId(),
            'pw' => $this->werbenetzwerk->getInterfacepasswort(),
            'uebrig' => 20,
            'reload' => 99999,
            'verguetung' => 0.0001,
            'ma' => 99999
        ]);

        $this->log("Response received:");
        $this->log($response);

        // Response parsen und verarbeiten
        return $this->processResponse($response, $kampagneType);
    }

    /**
     * Verarbeitet die API-Response
     */
    private function processResponse(string $response, string $kampagneType): array
    {
        $parts = explode('|', trim($response));

        $kampagnenCount = 0;
        $updatedCount = 0;
        $createdCount = 0;

        // Durch alle Kampagnen iterieren (je 5, 6 oder 7 Felder pro Kampagne)
        $i = 0;
        while ($i < count($parts)) {
            // Mindestens 5 Felder erforderlich
            if ($i + 4 >= count($parts)) {
                break;
            }

            // Erste 5 Felder auslesen
            $kid = $parts[$i];
            $linktext = $parts[$i + 1];
            $reload = (int) $parts[$i + 2] * 60; // API gibt Stunden zurück, DB speichert Minuten
            $uebrig = (int) $parts[$i + 3];
            $verdienst = (float) $parts[$i + 4];

            // Prüfen ob MA-Feld vorhanden ist (6. Feld)
            $ma = 0;
            $mailtext = null;
            $fieldsConsumed = 5;

            // Heuristik: Wenn das nächste Feld numerisch ist und klein, ist es wahrscheinlich MA
            if ($i + 5 < count($parts) && is_numeric($parts[$i + 5]) && $parts[$i + 5] < 1000) {
                $ma = (int) $parts[$i + 5];
                $fieldsConsumed = 6;

                // Prüfen ob Nachrichtentext vorhanden ist (7. Feld)
                if ($i + 6 < count($parts) && !is_numeric($parts[$i + 6])) {
                    $mailtext = $parts[$i + 6];
                    $fieldsConsumed = 7;
                }
            }

            $i += $fieldsConsumed;
            $kampagnenCount++;

            // Vergütung in Euro umrechnen
            $verguetungEuro = $verdienst * $this->werbenetzwerk->getUmrechnungskurs();

            // Kampagne verarbeiten
            if ($this->processKampagne($kid, $linktext, $ma, $reload, $uebrig, $verdienst, $verguetungEuro, $mailtext, $kampagneType)) {
                $updatedCount++;
            } else {
                $createdCount++;
            }
        }

        return [
            'total' => $kampagnenCount,
            'created' => $createdCount,
            'updated' => $updatedCount
        ];
    }

    /**
     * Verarbeitet eine einzelne Kampagne
     *
     * @return bool true wenn updated, false wenn created
     */
    private function processKampagne(
        string $kid,
        string $linktext,
        int $ma,
        int $reload,
        int $uebrig,
        float $verdienst,
        float $verguetungEuro,
        ?string $mailtext,
        string $kampagneType
    ): bool {
        // Vergütung höher als 0.1 Euro filtern
        if ($verguetungEuro > 0.1) {
            $this->log("Skipping: $linktext (KID: $kid, Vergütung zu hoch: $verguetungEuro €)");

            // Wenn Kampagne existiert, löschen
            $existingKampagne = $this->findExistingKampagneByType($kid, $kampagneType);
            if ($existingKampagne) {
                $this->entityManager->remove($existingKampagne);
                $this->log("  → Deleted existing campaign with high vergütung");
            }

            return false;
        }

        // Link-URL generieren
        $destUrl = match($kampagneType) {
            'is_ft' => "https://www.adcity.eu/codes/forcedtextlinkklick.php?id={USERID}&bid=$kid&aid={SEITENID}",
            'is_mail' => "https://www.adcity.eu/codes/paidmailklick.php?id={USERID}&bid=$kid&aid={SEITENID}",
            'is_tr' => "https://www.adcity.eu/codes/trafficklick.php?id={USERID}&bid=$kid&aid={SEITENID}",
            default => "https://www.adcity.eu/codes/kampagne.php?id={USERID}&bid=$kid&aid={SEITENID}"
        };

        $this->log("Processing: $linktext (KID: $kid, MA: $ma, Reload: $reload, Uebrig: $uebrig)");

        // Prüfen ob Kampagne bereits existiert
        $existingKampagne = $this->findExistingKampagneByType($kid, $kampagneType);

        if ($existingKampagne) {
            // Kampagne aktualisieren
            $existingKampagne->setVerguetung($verguetungEuro);
            $existingKampagne->setReload($reload);
            $existingKampagne->setUebrig($uebrig);
            $existingKampagne->setLinktext($linktext);
            $existingKampagne->setMa($ma);
            if ($mailtext) {
                $existingKampagne->setMailtext($mailtext);
                $existingKampagne->setIsMail(true);
            }

            $this->entityManager->persist($existingKampagne);
            $this->log("  → Updated (verguetung: $verguetungEuro €, reload: $reload, uebrig: $uebrig)");
            return true;
        } else {
            // Neue Kampagne erstellen
            $kampagne = new Kampagne();
            $kampagne->setDestUrl($destUrl);
            $kampagne->setKid($kid);
            $kampagne->setLinktext($linktext);
            $kampagne->setMa($ma);
            $kampagne->setReload($reload);
            $kampagne->setVerguetung($verguetungEuro);
            $kampagne->setUebrig($uebrig);
            $kampagne->setIsFb(false);
            $kampagne->setIsTr($kampagneType === 'is_tr');
            $kampagne->setIsFt($kampagneType === 'is_ft');
            $kampagne->setIsMail($kampagneType === 'is_mail');

            if ($mailtext && $kampagneType === 'is_mail') {
                $kampagne->setMailtext($mailtext);
            } elseif ($mailtext && $kampagneType === 'is_ft') {
                // ForcedTextlink kann auch Mailtext haben
                $kampagne->setMailtext($mailtext);
                $kampagne->setIsMail(true);
            }

            $kampagne->setUser($this->werbenetzwerkUser);

            $this->entityManager->persist($kampagne);
            $this->log("  → Created new campaign");
            return false;
        }
    }

    /**
     * Findet eine existierende Kampagne basierend auf Typ
     */
    private function findExistingKampagneByType(string $kid, string $kampagneType): ?Kampagne
    {
        $criteria = [
            'user' => $this->werbenetzwerkUser,
            'kid' => $kid,
            $kampagneType => true
        ];

        return $this->entityManager
            ->getRepository(Kampagne::class)
            ->findOneBy($criteria);
    }

    /**
     * Aktualisiert den Umrechnungskurs in der Datenbank
     */
    private function updateUmrechnungskurs(): void
    {
        $this->log("Updating Umrechnungskurs...");

        // Auf AdCity einloggen
        $this->loginToAdCity();

        // Umrechnungskurs von der Interface-Seite abrufen
        $umrechnungskurs = $this->fetchUmrechnungskurs();

        if ($umrechnungskurs !== null) {
            $this->werbenetzwerk->setUmrechnungskurs($umrechnungskurs);
            $this->entityManager->persist($this->werbenetzwerk);
            $this->entityManager->flush();
            $this->log("Umrechnungskurs updated: $umrechnungskurs");
        } else {
            $this->log("Warning: Could not fetch Umrechnungskurs");
        }

        // Cookie-Datei aufräumen
        if (file_exists($this->cookieFile)) {
            unlink($this->cookieFile);
        }
    }

    /**
     * Loggt sich auf AdCity.eu ein
     */
    private function loginToAdCity(): void
    {
        $this->log("Logging in to AdCity...");

        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => self::LOGIN_URL,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query([
                'username' => self::USERNAME,
                'password' => self::PASSWORD,
                'login' => 'Login'
            ]),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_COOKIEJAR => $this->cookieFile,
            CURLOPT_COOKIEFILE => $this->cookieFile,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200) {
            throw new \RuntimeException("Login failed with HTTP code: $httpCode");
        }

        $this->log("Login successful");
    }

    /**
     * Ruft den Umrechnungskurs von der Interface-Seite ab
     */
    private function fetchUmrechnungskurs(): ?float
    {
        $this->log("Fetching Umrechnungskurs from interface page...");

        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => self::INTERFACE_URL,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_COOKIEFILE => $this->cookieFile,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200 || !$response) {
            $this->log("Failed to fetch interface page (HTTP $httpCode)");
            return null;
        }

        // Umrechnungskurs aus der HTML-Response extrahieren
        // Suche nach Patterns wie "1 Pt = 0.0000000022 €" oder ähnlich
        $patterns = [
            '/1\s*Pt\s*=\s*([\d.]+)\s*€/i',
            '/1\s*pt\s*=\s*([\d.]+)\s*euro/i',
            '/Umrechnungskurs[:\s]*([\d.]+)/i',
            '/([\d.]+)\s*€\s*pro\s*Pt/i'
        ];

        foreach ($patterns as $pattern) {
            if (preg_match($pattern, $response, $matches)) {
                $umrechnungskurs = (float) $matches[1];
                $this->log("Found Umrechnungskurs: $umrechnungskurs");
                return $umrechnungskurs;
            }
        }

        $this->log("Could not find Umrechnungskurs in response");
        return null;
    }
}
