<?php
namespace Domain\Tasks;

class WorkTimeRepository
{
  private const UNSETTLED_TASK_STATUSES = [ 1, 3 ]; // do sprawdzenia, do rozliczenia
  private $mdb;

  public function __construct( $mdb = null )
  {
    if ( $mdb )
      $this -> mdb = $mdb;
    else
    {
      global $mdb;
      $this -> mdb = $mdb;
    }
  }

  public function getClientsWithUnsettledTasks()
  {
    $clients = $this -> mdb -> select( 'crm_client', '*', [ 'ORDER' => [ 'firm' => 'ASC' ] ] );
    $work_time = [];

    if ( !is_array( $clients ) or !count( $clients ) )
      return $work_time;

    foreach ( $clients as $client )
    {
      $task_rows = $this -> getClientTaskRows( (int)$client['id'] );
      $client['tasks'] = self::buildClientTasksByMonth( $task_rows, function( $task_id, $month ) {
        return (int)$this -> getTaskTotalTimeByMonth( $task_id, $month );
      } );

      if ( is_array( $client['tasks'] ) and count( $client['tasks'] ) )
        krsort( $client['tasks'] );

      $work_time[] = $client;
    }

    return $work_time;
  }

  public static function buildClientTasksByMonth( array $task_rows, callable $task_time_provider )
  {
    $tasks = [];
    $seen = [];

    foreach ( $task_rows as $row )
    {
      if ( !isset( $row['month'] ) or !isset( $row['id'] ) )
        continue;

      $month = (string)$row['month'];
      $task_id = (int)$row['id'];
      $dedupe_key = $task_id . ':' . $month;

      if ( isset( $seen[$dedupe_key] ) )
        continue;

      $seen[$dedupe_key] = true;

      $tasks[ $month ][] = [
        'id' => $task_id,
        'name' => $row['name'],
        'pay_rate' => $row['pay_rate'],
        'time' => (int)call_user_func( $task_time_provider, $task_id, $month )
      ];
    }

    return $tasks;
  }

  private function getClientTaskRows( $client_id )
  {
    $statuses = implode( ',', self::UNSETTLED_TASK_STATUSES );

    return $this -> mdb -> query(
      'SELECT DISTINCT '
      . 't.id, t.name, t.pay_rate, DATE_FORMAT(tw.date_end, \'%Y-%m\') AS month '
      . 'FROM tasks AS t '
      . 'INNER JOIN tasks_work AS tw ON t.id = tw.task_id '
      . 'WHERE t.status IN (' . $statuses . ') '
      . 'AND t.client_id = ' . (int)$client_id . ' '
      . 'AND tw.deleted = 0 '
      . 'AND tw.date_end IS NOT NULL '
      . 'ORDER BY month DESC, t.date_add DESC'
    ) -> fetchAll( \PDO::FETCH_ASSOC );
  }

  public static function getUnsettledTaskStatuses()
  {
    return self::UNSETTLED_TASK_STATUSES;
  }

  private function getTaskTotalTimeByMonth( $task_id, $month )
  {
    $seconds = 0;
    $date_from = $month . '-01 00:00:00';
    $date_to = $month . '-' . date( 't', strtotime( $month ) ) . ' 23:59:59';

    $rows = $this -> mdb -> select( 'tasks_work', [ 'date_start', 'date_end' ], [
      'AND' => [
        'deleted' => 0,
        'task_id' => (int)$task_id,
        'date_end[>=]' => $date_from,
        'date_end[<=]' => $date_to
      ],
      'ORDER' => [ 'id' => 'ASC' ]
    ] );

    if ( !is_array( $rows ) or !count( $rows ) )
      return 0;

    foreach ( $rows as $row )
    {
      if ( !$row['date_end'] )
        $row['date_end'] = date( 'Y-m-d H:i:s' );

      $seconds += strtotime( $row['date_end'] ) - strtotime( $row['date_start'] );
    }

    return $seconds;
  }
}
