<?php

namespace App\Browser\Jobs\HellcaseBattles;

use App\Browser\JobDebugScreenshot;
use App\Browser\Jobs\Hellcase\HellcaseJob;
use App\Models\HellcaseBattle;
use App\Models\Job;
use App\Models\JobArtifact;
use App\Models\JobRun;
use App\Notification\Notifications\JobDebugNotification;
use App\Notification\Providers\AllNotification;
use Exception;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverBy;
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Laravel\Dusk\Browser;

class HellcaseBattlesJob extends HellcaseJob implements ShouldBeUniqueUntilProcessing
{
    private Collection $jobInfos;
    private array $battlesToAdd = [];
    private array $battlesSent = [];

    public function __construct()
    {
        parent::__construct(3);
    }

    public function run(Browser $browser): ?JobRun
    {
        $this->jobInfos = Job::find($this->jobId)->jobInfosTable();
        Log::info("Running HellcaseBattlesJob");
        $this->jobRun = new JobRun([
            "job_id" => $this->jobId,
            "success" => false,
        ]);
        $this->jobRun->save();

        $browser->visit('https://hellcase.com');
        $browser->waitForText("CASES", 30, true);
        $this->removePopups($browser);
        sleep(5);
        $this->signin($browser);

        $this->saveInterestingBattles($browser);

        $this->sendFinishedBattles($browser);

        $this->jobRun->addArtifact(new JobArtifact([
            "name" => count($this->battlesSent) . " battailles envoyées",
        ]));

        $this->createNewBattles();

        $this->jobRun->addArtifact(new JobArtifact([
            "name" => count($this->battlesToAdd) . " nouvelles battailles ajoutées pour surveillage",
        ]));

        $this->jobRun->success = true;
        $this->jobRun->save();

        Log::info("HellcaseBattlesJob run ended");

        return $this->jobRun;
    }

    /**
     * Save current cases battles to database for later processing
     * @param \Laravel\Dusk\Browser $browser
     * @return void
     */
    private function saveInterestingBattles(Browser $browser)
    {
        $battleIndex = 0; // Index of the battle to get info from
        $running = true;
        while ($running) {
            $browser->visit('https://hellcase.com/casebattle');
            $browser->waitForText("CASES", 30, true);

            // Sort by price
            try {
                $sortByPriceDiv = $browser->driver->findElement(WebDriverBy::xpath("//*[span[contains(text(), 'Value')]]"));
                $sortByPriceDiv->click();
            } catch (Exception $e) {
                $browser->screenshot(JobDebugScreenshot::getFileName($this->jobId));
                AllNotification::send(new JobDebugNotification($this->jobId, "Failed to sort by price"));
                return;
            }

            sleep(5);

            $battles = $browser->driver->findElements(WebDriverBy::xpath("//*[contains(@class, 'casebattle-table__item')]"));
            $battle = $battles[$battleIndex];
            $battleIndex++;
            $browser->scrollIntoView(".casebattle-table__item:nth-child(" . max($battleIndex -1, 1) . ")");
            sleep(2);
            $battleValue = floatval(
                explode(
                    "\n",
                    $battle->findElement(WebDriverBy::xpath("./div/div[contains(@class, 'core-price')]"))->getDomProperty("innerText")
                )[1]
            );

            if ($battleValue < floatval($this->jobInfos->get("hellcase_battles_minimum_value"))) {
                $running = false;
                break;
            }

            $battleLinkButton = $battle->findElement(WebDriverBy::xpath("./div//button[.//*[text() = 'watch']]"));
            $battleLinkButton->sendKeys("\n");
            sleep(3);
            try { // If we still are on the casebattle page, it means the battle was cancelled or something else
                $browser->waitForLocation("https://hellcase.com/casebattle/", 3);
            } catch (Exception $e) {
                $battleLink = $browser->driver->getCurrentURL();

                $this->battlesToAdd[$battleLink] = $battleValue;
            }
        }
    }

    private function sendFinishedBattles(Browser $browser) {
        // foreach battle that we didn"t already planned to add with $this->battlesToAdd
        foreach (HellcaseBattle::all() as $battle) {
            if (!array_key_exists($battle->getUrl(), $this->battlesToAdd)) {
                $browser->visit($battle->getUrl());

                sleep(2);
                $browser->waitForText("Case Battle");

                if ($this->findElementContainingText($browser, "Started at:") != null) { // battle is finished
                    // Send the battle
                    $this->sendBattle($browser, $battle);
                }

                $battle->delete();
            }
        }
    }

    private function sendBattle(Browser $browser, HellcaseBattle $battle) {
        try {
            $battleHeader = $browser->driver->findElement(WebDriverBy::xpath("//*[contains(@class, 'case-battle-game__header')]"));
            sleep(2); // Wait for the animations to finish
            $battleHeader->takeElementScreenshot(HellcaseBattleScreenshot::getImgFileAbsolutePath());
        } catch (Exception $e) {
            $browser->screenshot(JobDebugScreenshot::getFileName($this->jobId));
            AllNotification::send(new JobDebugNotification($this->jobId, "Failed to screenshot battle"));
        }
        $this->battlesSent[$battle->getUrl()] = $battle->value;

        $options = [];

        if ($this->jobInfos->get("hellcase_battles_discord_webhook_url") !== null) { // Custom discord webhook
            $options["discord_webhook_url"] = $this->jobInfos->get("hellcase_battles_discord_webhook_url");
        }

        AllNotification::send(new HellcaseBattlesNofication($this->jobId, $battle), $options);
    }

    private function createNewBattles() {
        foreach ($this->battlesToAdd as $battleLink => $battleValue) {
            $battleLink = explode("/", $battleLink);
            try {
                HellcaseBattle::create([
                    "battle_id" => $battleLink[count($battleLink) - 1],
                    "value" => $battleValue,
                ]);
            } catch (Exception $e) {
            }
        }
    }
}
