<?php
namespace controls;
class Cron
{
  static public function cron_products()
  {
    global $mdb;

    if ( !$client_id = \S::get( 'client_id' ) )
    {
      echo "Nie podano ID klienta.";
      exit;
    }

    $client_bestseller_min_roas = \factory\Products::get_client_bestseller_min_roas( $client_id );

    $db_result = $mdb -> query( 'SELECT * FROM products AS p INNER JOIN products_history AS ph ON p.id = ph.product_id WHERE p.client_id = ' . $client_id ) -> fetchAll( \PDO::FETCH_ASSOC );

    $aggregated_data = [];

    foreach ( $db_result as $row )
    {
      $product_id = $row['product_id'];

      if ( !isset( $aggregated_data[$client_id] ) )
      {
        $aggregated_data[$client_id] = [];
      }

      if (!isset($aggregated_data[$client_id][$product_id]))
      {
        $aggregated_data[$client_id][$product_id] = [
          'product_id' => $product_id,
          'name' => $row['name'],
          'impressions' => 0,
          'clicks' => 0,
          'cost' => 0.0,
          'conversions' => 0,
          'conversions_value' => 0.0
        ];
      }

      $aggregated_data[$client_id][$product_id]['impressions'] += $row['impressions'];
      $aggregated_data[$client_id][$product_id]['clicks'] += $row['clicks'];
      $aggregated_data[$client_id][$product_id]['cost'] += $row['cost'];
      $aggregated_data[$client_id][$product_id]['conversions'] += $row['conversions'];
      $aggregated_data[$client_id][$product_id]['conversions_value'] += $row['conversions_value'];
    }

    $products_ids = $mdb -> select( 'products', 'id', [ 'client_id' => $client_id ] );
    foreach ( $products_ids as $product_id )
    {
      $products_ids_array[] = $product_id;
    }

    $mdb -> delete( 'products_temp', [ 'product_id' => $products_ids_array ] );

    foreach ( $aggregated_data as $client_offers )
    {
      foreach ( $client_offers as $offer_data )
      {
        // Obliczamy wartości CPC oraz conversions_price
        $cpc = $offer_data['clicks'] > 0 ? round( $offer_data['cost'] / $offer_data['clicks'], 6 ) : 0;
        $roas = ($offer_data['conversions'] > 0 and $offer_data['cost']) ? round($offer_data['conversions_value'] / $offer_data['cost'], 2) * 100 : 0;

        $impressions_30 = \factory\Products::get_impressions_30( $offer_data['product_id'] );

        // update custom_label_4 only current is empty or is bestseller
        $custom_label_4 = \factory\Products::get_product_data( $offer_data['product_id'], 'custom_label_4' );
        if ( $custom_label_4 == null || $custom_label_4 == 'bestseller' and (int)$client_bestseller_min_roas > 0 )
        {
          if ( $roas > $client_bestseller_min_roas and $offer_data['conversions'] > 10 )
          {
            $new_custom_label_4 = 'bestseller';
          }
          else
          {
            $new_custom_label_4 = null;
          }

          $offers_data_tmp = $mdb -> get( 'products_data', '*', [ 'product_id' => $offer_data['product_id'] ] );
          if ( isset( $offers_data_tmp['id'] ) )
          {
            if ( $new_custom_label_4 != $offers_data_tmp['custom_label_4'] )
              $mdb -> insert( 'products_comments', [
                'product_id' => $offer_data['product_id'],
                'comment' => 'Zmiana pola "custom_label_4" na: ' . $new_custom_label_4,
                'type' => 1,
                'date_add' => date( 'Y-m-d' )
              ] );

            $mdb -> update( 'products_data', [
              'custom_label_4' => $new_custom_label_4
            ], [ 'id' => $offers_data_tmp['id'] ] );
          }
          else
          {
            $mdb -> insert( 'products_data', [
              'product_id' => $offer_data['product_id'],
              'custom_label_4' => $new_custom_label_4
            ] );

            if ( $new_custom_label_4 == 'bestseller' )
            {
              $mdb -> insert( 'products_comments', [
                'product_id' => $offer_data['product_id'],
                'comment' => 'Zmiana pola "custom_label_4" na: bestseller',
                'type' => 1,
                'date_add' => date( 'Y-m-d' )
              ] );
            }
          }
        }

        // if ( $impressions_30 <= 30 )
        //   $custom_label_3 = 'product_zombie';
        // else
        //   $custom_label_3 = null;

        // $offers_data_tmp = $mdb -> get( 'products_data', '*', [ 'product_id' => $offer_data['product_id'] ] );
        // if ( isset( $offers_data_tmp['id'] ) )
        // {
        //   if ( $custom_label_3 != $offers_data_tmp['custom_label_3'] )
        //     $mdb -> insert( 'products_comments', [
        //       'product_id' => $offer_data['product_id'],
        //       'comment' => 'Zmiana pola "custom_label_3" na: ' . $custom_label_3,
        //       'type' => 1,
        //       'date_add' => date( 'Y-m-d' )
        //     ] );

        //   $mdb -> update( 'products_data', [
        //     'custom_label_3' => $custom_label_3
        //   ], [ 'id' => $offers_data_tmp['id'] ] );
        // }
        // else
        // {
        //   $mdb -> insert( 'products_data', [
        //     'product_id' => $offer_data['product_id'],
        //     'custom_label_3' => $custom_label_3
        //   ] );

        //   if ( $custom_label_3 == 'product_zombie' )
        //   {
        //     $mdb -> insert( 'products_comments', [
        //       'product_id' => $offer_data['product_id'],
        //       'comment' => 'Zmiana pola "custom_label_3" na: product_zombie',
        //       'type' => 1,
        //       'date_add' => date( 'Y-m-d' )
        //     ] );
        //   }
        // }

        // Zapisujemy każdy zsumowany wpis do offers_temp
        $clicks_30 = \factory\Products::get_clicks_30( $offer_data['product_id'] );

        $mdb -> insert( 'products_temp', [
          'product_id' => $offer_data['product_id'],
          'name' => $offer_data['name'],
          'impressions' => $offer_data['impressions'],
          'impressions_30' => $impressions_30,
          'clicks' => $offer_data['clicks'],
          'clicks_30' => $clicks_30,
          'ctr' => round( $offer_data['clicks'] / $offer_data['impressions'], 4 ) * 100,
          'cost' => $offer_data['cost'],
          'conversions' => $offer_data['conversions'],
          'conversions_value' => $offer_data['conversions_value'],
          'cpc' => $cpc,
          'roas' => $roas,
        ]);
      }
    }

    echo json_encode( [ 'result' => "Agregacja zakończona, dane zapisane do offers_temp." ] );
    exit;
  }

  static public function cron_products_history_30()
  {
    global $mdb;

    $start_time = microtime(true);

    $client_id = \S::get( 'client_id' );

    if ( !$client_id )
    {
      echo json_encode( [ 'result' => "Nie podano ID klienta." ] );
      exit;
    }

    $products = $mdb -> select( 'products', 'id', [ 'client_id' => $client_id ] );
    foreach ( $products as $product )
    {
      $dates = $mdb -> query( 'SELECT id, date_add FROM products_history WHERE product_id = ' . $product . ' AND updated = 1 ORDER BY date_add DESC' ) -> fetchAll( \PDO::FETCH_ASSOC );
      foreach ( $dates as $date )
      {
        self::cron_product_history_30_save( $product, $date['date_add'] );
        $mdb -> update( 'products_history', [ 'updated' => 0 ], [ 'id' => $date['id'] ] );
      }
    }

    $end_time = microtime(true);
    $execution_time = $end_time - $start_time;
    echo json_encode( [ 'result' => "Agregacja zakończona, dane zapisane do offers_history_30. Czas wykonania skryptu: " . round($execution_time, 4) . " sekund." ] );
    exit;
  }

  static public function get_roas_all_time( $product_id, $date_to )
  {
    global $mdb;

    $roas_all_time = $mdb -> query( 'SELECT SUM(conversions_value) / SUM(cost) * 100 AS roas_all_time FROM products_history WHERE product_id = ' . $product_id . ' AND date_add <= \'' . $date_to . '\'' ) -> fetchColumn();
    return round( $roas_all_time, 2 );
  }

  static public function cron_product_history_30_save( $product_id, $date_to )
  {
    global $mdb;

    $data = $mdb -> query( 'SELECT * FROM products_history WHERE product_id = ' . $product_id . ' AND date_add <= \'' . $date_to . '\' ORDER BY date_add DESC LIMIT 30' ) -> fetchAll( \PDO::FETCH_ASSOC );

    // Inicjalizacja tablic do przechowywania danych
    $offers_data = [];

    // Grupowanie danych według produktów
    foreach ( $data as $entry )
    {
      if ( !isset( $offers_data[$product_id] ) )
      {
        $offers_data[$product_id] = [
          'impressions' => 0,
          'clicks' => 0,
          'cost' => 0.0,
          'conversions' => 0,
          'conversions_value' => 0.0,
          'roas' => 0,
          'days_counted' => []
        ];
      }

      // Sumowanie danych według produktu
      $offers_data[$product_id]['impressions'] += $entry['impressions'];
      $offers_data[$product_id]['clicks'] += $entry['clicks'];
      $offers_data[$product_id]['cost'] += $entry['cost'];
      $offers_data[$product_id]['conversions'] += $entry['conversions'];
      $offers_data[$product_id]['conversions_value'] += $entry['conversions_value'];
      $offers_data[$product_id]['days_counted'][] = $entry['date_add'];
    }

    foreach ( $offers_data as $offer )
    {
      $day_count = count( $offer['days_counted'] );

      $impressions = $offer['impressions'];
      $clicks = $offer['clicks'];
      $ctr = ( $clicks > 0 and $impressions ) ? round( $clicks / $impressions, 4 ) * 100 : 0;
      $cost = $offer['cost'];
      $conversions = $offer['conversions'];
      $conversions_value = $offer['conversions_value'];
      $roas = ( $conversions_value > 0 and $cost ) ? round( $conversions_value / $cost, 2 ) * 100 : 0;

      if ( $mdb -> count( 'products_history', [ 'AND' => [ 'product_id' => $product_id, 'date_add[<=]' => $date_to ] ] ) >= 14 )
      {
        if ( $mdb -> count( 'products_history_30', [ 'AND' => [ 'product_id' => $product_id, 'date_add' => $date_to ] ] ) > 0 )
        {
          $mdb -> update( 'products_history_30', [
            'impressions' => $impressions,
            'clicks' => $clicks,
            'ctr' => $ctr,
            'cost' => $cost,
            'conversions' => $conversions,
            'conversions_value' => $conversions_value,
            'roas' => $roas,
            'roas_all_time' => self::get_roas_all_time( $product_id, $date_to )
          ], [ 'AND' => [ 'product_id' => $product_id, 'date_add' => $date_to ] ] );
        }
        else
        {
          $mdb -> insert( 'products_history_30', [
            'product_id' => $product_id,
            'impressions' => $impressions,
            'clicks' => $clicks,
            'ctr' => $ctr,
            'cost' => $cost,
            'conversions' => $conversions,
            'conversions_value' => $conversions_value,
            'roas' => $roas,
            'roas_all_time' => self::get_roas_all_time( $product_id, $date_to ),
            'date_add' => $date_to
          ] );
        }
      }
    }
  }

  static public function cron_xml()
  {
    global $mdb;

    if ( !$client_id = \S::get( 'client_id' ) )
    {
      echo json_encode( [ 'result' => "Nie podano ID klienta." ] );
      exit;
    }

    $results = $mdb -> query( 'SELECT * FROM products AS p INNER JOIN products_data AS pd ON p.id = pd.product_id WHERE p.client_id = ' . $client_id ) -> fetchAll( \PDO::FETCH_ASSOC );

    $doc = new \DOMDocument('1.0', 'UTF-8');
    $xmlRoot = $doc->createElement('rss');
    $xmlRoot = $doc->appendChild($xmlRoot);
    $xmlRoot->setAttribute('version', '2.0');
    $xmlRoot->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:g', 'http://base.google.com/ns/1.0');

    $channelNode = $xmlRoot->appendChild($doc->createElement('channel'));
    $channelNode->appendChild($doc->createElement('title', 'Custom Feed'));
    $channelNode->appendChild($doc->createElement('link', 'https://ads.pagedev.pl'));

    $fieldMappings = [
      'title' => 'g:title',
      'custom_label_4' => 'g:custom_label_4',
      'custom_label_3' => 'g:custom_label_3',
    ];

    foreach ($results as $row)
    {
      $hasValidField = false;
      foreach ($fieldMappings as $dbField => $xmlTag) {
          if (!empty($row[$dbField])) {
              $hasValidField = true;
              break;
          }
      }

      if ( $hasValidField )
      {
        $itemNode = $channelNode->appendChild($doc->createElement('item'));

        $offer_id = $mdb -> get( 'products', 'offer_id', [ 'id' => $row['product_id'] ] );

        $p_gid = $itemNode->appendChild($doc->createElement('g:id', $offer_id));

        foreach ($fieldMappings as $dbField => $xmlTag) {
          if (!empty($row[$dbField])) {
              $itemNode->appendChild($doc->createElement($xmlTag, $row[$dbField]));
          }
        }
      }
    }

    file_put_contents('xml/custom-feed-' . $_GET['client_id'] . '.xml', $doc->saveXML());

    echo json_encode( [ 'result' => "Plik XML został wygenerowany <a href=\"https://adspro.projectpro.pl/xml/custom-feed-" . $_GET['client_id'] . ".xml\">https://adspro.projectpro.pl/xml/custom-feed-" . $_GET['client_id'] . ".xml</a>." ] );
    exit;
  }

  static public function cron_phrases()
  {
    global $mdb;

    if ( !$client_id = \S::get( 'client_id' ) )
    {
      echo json_encode( [ 'result' => "Nie podano ID klienta." ] );
      exit;
    }

    $data = $mdb -> query( 'SELECT * FROM phrases AS p INNER JOIN phrases_history AS ph ON p.id = ph.phrase_id WHERE p.client_id = ' . $client_id ) -> fetchAll( \PDO::FETCH_ASSOC );

    $aggregated_data = [];

    foreach ( $data as $row )
    {
      $phrase_id = $row['phrase_id'];

      if ( !isset( $aggregated_data[$client_id] ) )
      {
        $aggregated_data[$client_id] = [];
      }

      if ( !isset( $aggregated_data[$client_id][$phrase_id] ) )
      {
        $aggregated_data[$client_id][$phrase_id] = [
          'phrase_id' => $phrase_id,
          'phrase' => $row['phrase'],
          'impressions' => 0,
          'clicks' => 0,
          'cost' => 0.0,
          'conversions' => 0,
          'conversions_value' => 0.0
        ];
      }

      $aggregated_data[$client_id][$phrase_id]['impressions'] += $row['impressions'];
      $aggregated_data[$client_id][$phrase_id]['clicks'] += $row['clicks'];
      $aggregated_data[$client_id][$phrase_id]['cost'] += $row['cost'];
      $aggregated_data[$client_id][$phrase_id]['conversions'] += $row['conversions'];
      $aggregated_data[$client_id][$phrase_id]['conversions_value'] += $row['conversions_value'];
    }

    $phrases_ids = $mdb -> select( 'phrases', 'id', [ 'client_id' => $client_id ] );
    foreach ( $phrases_ids as $phrase_id )
    {
      $phrases_ids_array[] = $phrase_id -> id;
    }

    $mdb -> delete( 'phrases_temp', [ 'phrase_id' => $phrases_ids_array ] );

    foreach ( $aggregated_data as $client_phrases )
    {
      foreach ( $client_phrases as $phrase_data )
      {
        $cpc = $phrase_data['clicks'] > 0 ? round( $phrase_data['cost'] / $phrase_data['clicks'], 6 ) : 0;
        $roas = ( $phrase_data['conversions'] > 0 and $phrase_data['cost'] ) ? round( $phrase_data['conversions_value'] / $phrase_data['cost'], 2 ) * 100 : 0;

        $mdb -> insert( 'phrases_temp', [
          'phrase_id' => $phrase_data['phrase_id'],
          'phrase' => $phrase_data['phrase'],
          'impressions' => $phrase_data['impressions'],
          'clicks' => $phrase_data['clicks'],
          'cost' => $phrase_data['cost'],
          'conversions' => $phrase_data['conversions'],
          'conversions_value' => $phrase_data['conversions_value'],
          'cpc' => $cpc,
          'roas' => $roas,
        ] );
      }
    }

    echo json_encode( [ 'result' => "Agregacja zakończona, dane zapisane do phrases_temp." ] );
    exit;
  }

  static public function cron_phrases_history_30()
  {
    global $mdb;

    $start_time = microtime( true ); // Rozpoczęcie mierzenia czasu

    $client_id = \S::get( 'client_id' ); // Pobranie ID klienta

    if ( !$client_id ) // Jeśli nie podano ID klienta
    {
      echo json_encode( [ 'result' => "Nie podano ID klienta." ] ); // Wyświetlenie komunikatu
      exit; // Zakończenie działania skryptu
    }

    // Pobranie bieżącej daty i daty sprzed 30 dni
    $phrases = $mdb -> query( 'SELECT * FROM phrases WHERE client_id = ' . $client_id ) -> fetchAll( \PDO::FETCH_ASSOC ); // Pobranie fraz dla danego klienta

    foreach ( $phrases as $phrase )
    {
      for ( $i = 0; $i < 30; $i++ )
      {
        $date_to = date( 'Y-m-d', strtotime( '-' . ( 1 + $i ) . ' days' ) );
        $date_from = date( 'Y-m-d', strtotime( '-' . ( 31 + $i ) . ' days' ) );

        $data_updated = false;

        if ( $mdb -> count( 'phrases_history', [ 'AND' => [ 'phrase_id' => $phrase['id'], 'date_add[>=]' => $date_from, 'date_add[<=]' => $date_to, 'updated' => 1 ] ] ) > 0 )
        {
          $data_updated = true;
        }

        if ( $data_updated )
        {
          self::cron_phrase_history_30_save( $phrase['id'], $date_from, $date_to );
        }
      }

      $mdb -> update( 'phrases_history', [ 'updated' => 0 ], [ 'AND' => [ 'phrase_id' => $phrase['id'], 'updated' => 1 ] ] );
    }

    $end_time = microtime( true ); // Zakończenie mierzenia czasu
    $execution_time = $end_time - $start_time; // Obliczenie czasu wykonania

    echo json_encode( [ 'result' => "Agregacja zakończona, dane zapisane do phrases_history_30. Czas wykonania skryptu: " . round( $execution_time, 4 ) . " sekund." ] ); // Wyświetlenie komunikatu
    exit;
  }

  static public function cron_phrase_history_30_save( $phrase_id, $date_from, $date_to )
  {
    global $mdb;

    $data = $mdb -> query( 'SELECT * FROM phrases_history WHERE phrase_id = ' . $phrase_id . ' AND date_add >= \'' . $date_from . '\' AND date_add <= \'' . $date_to . '\' ORDER BY date_add ASC' ) -> fetchAll( \PDO::FETCH_ASSOC );

    // Inicjalizacja tablic do przechowywania danych
    $phrases_data = [];

    // Grupowanie danych według fraz
    foreach ( $data as $entry )
    {
      $phrase_id = $entry['phrase_id'];

      if ( !isset( $phrases_data[$phrase_id] ) )
      {
        $phrases_data[$phrase_id] = [
          'impressions' => 0,
          'clicks' => 0,
          'cost' => 0.0,
          'conversions' => 0,
          'conversions_value' => 0.0,
          'roas' => 0,
          'days_counted' => []
        ];
      }

      // Sumowanie danych według fraz
      $phrases_data[$phrase_id]['impressions'] += $entry['impressions'];
      $phrases_data[$phrase_id]['clicks'] += $entry['clicks'];
      $phrases_data[$phrase_id]['cost'] += $entry['cost'];
      $phrases_data[$phrase_id]['conversions'] += $entry['conversions'];
      $phrases_data[$phrase_id]['conversions_value'] += $entry['conversions_value'];
      $phrases_data[$phrase_id]['days_counted'][] = $entry['date_add'];
    }

    foreach ( $phrases_data as $phrase )
    {
      $day_count = count( $phrase['days_counted'] );

      $impressions = $phrase['impressions'] / $day_count;
      $clicks = $phrase['clicks'] / $day_count;
      $cost = $phrase['cost'] / $day_count;
      $conversions = $phrase['conversions'] / $day_count;
      $conversions_value = $phrase['conversions_value'] / $day_count;
      $roas = ( $conversions_value > 0 and $cost ) ? round( $conversions_value / $cost, 2 ) * 100 : 0;

      if ( $day_count > 14 )
      {
        if ( $mdb -> count( 'phrases_history_30', [ 'AND' => [ 'phrase_id' => $phrase_id, 'date_add' => $date_to ] ] ) > 0 )
        {
          $mdb -> update( 'phrases_history_30', [
            'impressions' => $impressions,
            'clicks' => $clicks,
            'cost' => $cost,
            'conversions' => $conversions,
            'conversions_value' => $conversions_value,
            'roas' => $roas
          ], [ 'AND' => [ 'phrase_id' => $phrase_id, 'date_add' => $date_to ] ] );
        }
        else
        {
          $mdb -> insert( 'phrases_history_30', [
            'phrase_id' => $phrase_id,
            'impressions' => $impressions,
            'clicks' => $clicks,
            'cost' => $cost,
            'conversions' => $conversions,
            'conversions_value' => $conversions_value,
            'roas' => $roas,
            'date_add' => $date_to
          ] );
        }
      }
    }
  }
}
