<?php
namespace factory;
class Finances
{
  static public function first_operation_date()
  {
    global $mdb;
    return $mdb -> get( 'finance_operations', 'date', [ 'ORDER' => [ 'date' => 'ASC' ] ] );
  }

  static public function get_operation_tags( int $operation_id )
  {
    global $mdb;

    $tags_id = $mdb -> select( 'finance_operation_tags', 'tag_id', [ 'operation_id' => $operation_id ] );
    foreach ( $tags_id as $tag_id )
    {
      if ( $return )
        $return .= ', ';
      $return .= $mdb -> get( 'finance_tags', 'tag', [ 'id' => $tag_id ] );
    }
    return $return;
  }

  static public function client_name( $client_id )
  {
    global $mdb;
    return $mdb -> get( 'crm_client', 'firm',[ 'id' => $client_id ] );
  }

  static public function clients_list_by_dates( $date_from, $date_to )
  {
    global $mdb;
    return $mdb -> query( 'SELECT cc.id, cc.firm FROM crm_client AS cc INNER JOIN finance_operations AS fo ON fo.client_id = cc.id WHERE date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' GROUP BY cc.id ORDER BY firm ASC' ) -> fetchAll( \PDO::FETCH_ASSOC );
  }

  static public function clients_list()
  {
    global $mdb;
    return $mdb -> select( 'crm_client', [ 'id', 'firm' ], [ 'ORDER' => [ 'firm' => 'ASC' ] ] );
  }

  public static function category_delete( $category_id ) {
    global $mdb;
    return $mdb -> delete( 'finance_categories', [ 'id' => (int)$category_id ] );
  }

  public static function default_group()
  {
    global $mdb;
    return $mdb -> get( 'finance_group', 'id', [ 'default_group' => 1 ] );
  }

  public static function groups_list()
  {
    global $mdb;
    return $mdb -> select( 'finance_group', '*', [ 'ORDER' => [ 'name' => 'ASC' ] ] );
  }

  public static function operation_delete( $operation_id )
  {
    global $mdb;
    return $mdb -> delete( 'finance_operations', [ 'id' => $operation_id ] );
  }

  public static function tags_json( $group_id )
  {
    global $mdb;
    return $mdb -> select( 'finance_tags', 'tag', [ 'group_id' => $group_id, 'ORDER' => [ 'tag' => 'ASC' ] ] );
  }

  public static function tags_list( $group_id )
  {
    global $mdb;

    $results = $mdb -> select( 'finance_tags', '*', [ 'group_id' => $group_id ] );
    if ( is_array( $results ) and !empty( $results ) ) foreach ( $results as $row )
    {
      $tag = $row;
      $tag['count'] = $mdb -> count( 'finance_operation_tags', [ 'tag_id' => $row['id'] ] );

      $tags[] = $tag;
    }

    if ( is_array( $tags ) and count( $tags ) )
      array_multisort( array_column( $tags, "count" ), SORT_DESC, $tags );

    return $tags;
  }

  static public function operations_list( $date_from, $date_to, $group_id ) {
    global $mdb;
    $results = $mdb -> query( 'SELECT '
                                  . 'fo.*, fc.name '
                                . 'FROM '
                                  . 'finance_operations AS fo '
                                  . 'INNER JOIN finance_categories AS fc ON fc.id = fo.category_id '
                                . 'WHERE '
                                  . 'date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND group_id = ' . $group_id . ' '
                                . 'ORDER BY '
                                  . 'fo.date DESC, id DESC' ) -> fetchAll( \PDO::FETCH_ASSOC );
    return $results;
  }

  public static function operation_details( $operation_id )
  {
    global $mdb;

    $operation = $mdb -> get( 'finance_operations', '*', [ 'id' => $operation_id ] );
    $operation['tags'] = $mdb -> query( 'SELECT tag, tag_id FROM finance_operation_tags AS fot INNER JOIN finance_tags AS ft ON fot.tag_id = ft.id WHERE operation_id = ' . (int)$operation_id ) -> fetchAll( \PDO::FETCH_ASSOC );

    return $operation;
  }

  public static function operation_save( $operation_id, $category_id, $date, $amount, $description, $tags, $group_id )
  {
    global $mdb;

    if ( !$operation_id )
    {
      $mdb -> insert( 'finance_operations', [
                'date' => $date ? $date : date( 'Y-m-d' ),
                'category_id' => $category_id,
                'amount' => $amount,
                'description' => $description
              ] );

      $id = $mdb -> id();

      $tags = explode( ',', $tags );
      if ( is_array( $tags ) ) foreach ( $tags as $tag )
      {
        if ( $tag_id = $mdb -> get( 'finance_tags', 'id', [ 'AND' => [ 'group_id' => $group_id, 'tag' => trim( $tag ) ] ] ) )
          $mdb -> insert( 'finance_operation_tags', [ 'operation_id' => $id, 'tag_id' => $tag_id ] );
        else
        {
          $mdb -> insert( 'finance_tags', [ 'tag' => trim( $tag ), 'group_id' => $group_id ] );
          $tag_id = $mdb -> id();
          $mdb -> insert( 'finance_operation_tags', [ 'operation_id' => $id, 'tag_id' => $tag_id ] );
        }
      }
      return $id;
    }
    else
    {
      $mdb -> update( 'finance_operations', [
                'date' => $date,
                'amount' => $amount,
                'description' => $description
              ], [
                'id' => $operation_id
              ] );

      $mdb -> delete( 'finance_operation_tags', [ 'operation_id' => $operation_id ] );

      $tags = explode( ',', $tags );
      if ( is_array( $tags ) ) foreach ( $tags as $tag )
      {
        if ( $tag_id = $mdb -> get( 'finance_tags', 'id', [ 'AND' => [ 'group_id' => $group_id, 'tag' => trim( $tag ) ] ] ) )
          $mdb -> insert( 'finance_operation_tags', [ 'operation_id' => $operation_id, 'tag_id' => $tag_id ] );
        else
        {
          $mdb -> insert( 'finance_tags', [ 'tag' => trim( $tag ), 'group_id' => $group_id ] );
          $tag_id = $mdb -> id();
          $mdb -> insert( 'finance_operation_tags', [ 'operation_id' => $operation_id, 'tag_id' => $tag_id ] );
        }
      }
      return $operation_id;
    }
  }
  public static function category_details( $category_id )
  {
    global $mdb;
    return $mdb -> get( 'finance_categories', '*', [ 'id' => $category_id ] );
  }

  public static function category_save( $category_id, $name, $parent_id, $group_id )
  {
    global $mdb;

    if ( !$category_id )
    {
      $mdb -> insert( 'finance_categories', [
                'name' => $name,
                'parent_id' => $parent_id ? $parent_id : null,
                'group_id' => $group_id
              ] );
      return $mdb -> id();
    }
    else
    {
      $mdb -> update( 'finance_categories', [
                'name' => $name,
                'group_id' => $group_id
              ], [
                'id' => $category_id
              ] );
      return $category_id;
    }
    return false;
  }

  static public function wallet_expenses_this_month( $group_id )
  {
    global $mdb;

    $date_from = date( 'Y-m-01', strtotime( date( 'Y-m-d' ) ) );
    $date_to = date( 'Y-m-t', strtotime( date( 'Y-m-d' ) ) );

    $results = $mdb -> query( 'SELECT SUM(amount) AS wallet_expenses_this_month FROM finance_operations WHERE category_id IN ( SELECT id FROM finance_categories WHERE group_id = ' . $group_id . ' ) AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount < 0' ) -> fetchAll( \PDO::FETCH_ASSOC );
    return $results[0]['wallet_expenses_this_month'];
  }

  static public function wallet_income_this_month( $group_id )
  {
    global $mdb;

    $date_from = date( 'Y-m-01', strtotime( date( 'Y-m-d' ) ) );
    $date_to = date( 'Y-m-t', strtotime( date( 'Y-m-d' ) ) );

    $results = $mdb -> query( 'SELECT SUM(amount) AS wallet_income_this_month FROM finance_operations WHERE category_id IN ( SELECT id FROM finance_categories WHERE group_id = ' . $group_id . ' ) AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount > 0' ) -> fetchAll( \PDO::FETCH_ASSOC );
    return $results[0]['wallet_income_this_month'];
  }

  static public function wallet_summary_this_month( $group_id )
  {
    global $mdb;

    $date_from = date( 'Y-m-01', strtotime( date( 'Y-m-d' ) ) );
    $date_to = date( 'Y-m-t', strtotime( date( 'Y-m-d' ) ) );

    $results = $mdb -> query( 'SELECT SUM(amount) AS wallet_summary_this_month FROM finance_operations WHERE category_id IN ( SELECT id FROM finance_categories WHERE group_id = ' . $group_id . ' ) AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\'' ) -> fetchAll( \PDO::FETCH_ASSOC );
    return $results[0]['wallet_summary_this_month'];
  }

  static public function wallet_summary( $group_id )
  {
    global $mdb;

    $results = $mdb -> query( 'SELECT SUM(amount) AS wallet_summary FROM finance_operations WHERE category_id IN ( SELECT id FROM finance_categories WHERE group_id = ' . $group_id . ' )' ) -> fetchAll( \PDO::FETCH_ASSOC );
    return $results[0]['wallet_summary'];
  }

  public static function operations( $category_id, $date_from, $date_to, $tag_id = null )
  {
    global $mdb;

    if ( $tag_id )
      $results = $mdb -> query( 'SELECT '
                                    . 'fo.*, firm '
                                  . 'FROM '
                                    . 'finance_operations AS fo '
                                    . 'INNER JOIN finance_operation_tags AS fot ON fot.operation_id = fo.id '
                                    . 'INNER JOIN crm_client AS cc ON fo.client_id = cc.id '
                                  . 'WHERE '
                                      . 'category_id = ' . $category_id . ' AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' '
                                    . 'AND '
                                      . 'tag_id = :tag_id '
                                  . 'ORDER BY date DESC, id DESC ',
                                  [
                                    ':tag_id' => (int)$tag_id
                                  ] ) -> fetchAll();
    else
      $results = $mdb -> query( 'SELECT fo.* FROM finance_operations AS fo WHERE category_id = ' . $category_id . ' AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' ORDER BY date DESC, fo.id DESC ' ) -> fetchAll();
    if ( is_array( $results ) ) foreach ( $results as $row )
    {
      $row['tags'] = $mdb -> query( 'SELECT tag FROM finance_operation_tags AS fot INNER JOIN finance_tags AS ft ON fot.tag_id = ft.id WHERE operation_id = ' . $row['id'] ) -> fetchAll( \PDO::FETCH_ASSOC );
      $operations[] = $row;
    }
    return $operations;
  }

  public static function categories( $date_from, $date_to, $tag_id = '', $parent_id = null, $group_id )
  {
    global $mdb;

    $results = $mdb -> select( 'finance_categories', [ 'id', 'name' ], [ 'AND' => [ 'group_id' => $group_id, 'parent_id' => $parent_id ], 'ORDER' => [ 'name' => 'ASC' ] ] );
    if ( is_array( $results ) and !empty( $results ) ) foreach ( $results as $row )
    {
      if ( $tag_id )
      {
        $results2 = $mdb -> query( 'SELECT '
                                        . 'SUM(amount) '
                                      . 'FROM '
                                        . 'finance_operations AS fo '
                                        . 'INNER JOIN finance_categories AS fc ON fc.id = fo.category_id '
                                        . 'INNER JOIN finance_operation_tags AS fot ON fot.operation_id = fo.id '
                                        . 'INNER JOIN finance_tags AS ft ON ft.id = fot.tag_id '
                                      . 'WHERE '
                                        . 'category_id = ' . $row['id'] . ' AND tag_id = ' . $tag_id . ' AND ft.group_id = ' . $group_id . ' AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount < 0' ) -> fetchAll();
        $row['costs'] = (double)$results2[0][0];

        $results2 = $mdb -> query( 'SELECT '
                                        . 'COUNT(fo.id) '
                                      . 'FROM '
                                        . 'finance_operations AS fo '
                                        . 'INNER JOIN finance_categories AS fc ON fc.id = fo.category_id '
                                        . 'INNER JOIN finance_operation_tags AS fot ON fot.operation_id = fo.id'
                                        . 'INNER JOIN finance_tags AS ft ON ft.id = fot.tag_id '
                                      . ' WHERE '
                                        . 'category_id = ' . $row['id'] . ' AND tag_id = ' . $tag_id . ' AND ft.group_id = :group_id AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount < 0', [
                      ':group_id' => $group_id
                    ] ) -> fetchAll();
        $row['costs_count'] = (int)$results2[0][0];

        $results2 = $mdb -> query( 'SELECT '
                                        . 'SUM(amount) '
                                      . 'FROM '
                                        . 'finance_operations AS fo '
                                        . 'INNER JOIN finance_categories AS fc ON fc.id = fo.category_id '
                                        . 'INNER JOIN finance_operation_tags AS fot ON fot.operation_id = fo.id '
                                        . 'INNER JOIN finance_tags AS ft ON ft.id = fot.tag_id '
                                      . 'WHERE '
                                        . 'category_id = ' . $row['id'] . ' AND tag_id = ' . $tag_id . ' AND ft.group_id = :group_id AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount > 0', [
                      ':group_id' => $group_id
                    ] ) -> fetchAll();
        $row['income'] = (double)$results2[0][0];

        $results2 = $mdb -> query( 'SELECT '
                                        . 'COUNT(fo.id) '
                                      . 'FROM '
                                        . 'finance_operations AS fo '
                                        . 'INNER JOIN finance_categories AS fc ON fc.id = fo.category_id '
                                        . 'INNER JOIN finance_operation_tags AS fot ON fot.operation_id = fo.id '
                                        . 'INNER JOIN finance_tags AS ft ON ft.id = fot.tag_id '
                                      . 'WHERE '
                                        . 'category_id = ' . $row['id'] . ' AND tag_id = ' . $tag_id . ' AND ft.group_id = :group_id AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount > 0', [
                      ':group_id' => $group_id
                    ] ) -> fetchAll();
        $row['income_count'] = (int)$results2[0][0];
      }
      else
      {
        $results2 = $mdb -> query( 'SELECT SUM(amount) FROM finance_operations WHERE category_id = ' . $row['id'] . ' AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount < 0' ) -> fetchAll();
        $row['costs'] = $results2[0][0];

        $results2 = $mdb -> query( 'SELECT COUNT(0) FROM finance_operations WHERE category_id = ' . $row['id'] . ' AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount < 0' ) -> fetchAll();
        $row['costs_count'] = (int)$results2[0][0];

        $results2 = $mdb -> query( 'SELECT SUM(amount) FROM finance_operations WHERE category_id = ' . $row['id'] . ' AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount > 1' ) -> fetchAll();
        $row['income'] = $results2[0][0];

        $results2 = $mdb -> query( 'SELECT COUNT(0) FROM finance_operations WHERE category_id = ' . $row['id'] . ' AND date >= \'' . $date_from . '\' AND date <= \'' . $date_to . '\' AND amount > 1' ) -> fetchAll();
        $row['income_count'] = (int)$results2[0][0];
      }

      $row['subcategories'] = self::categories( $date_from, $date_to, $tag_id, $row['id'], $group_id, $client_id );
      $categories[] = $row;
    }
    return $categories;
  }
}
