<?php
declare(strict_types=1);
error_reporting(-1);

set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
    // Не выбрасываем исключение если ошибка подавлена с
    // помощью оператора @
    if (!error_reporting()) {
        return;
    }

    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
});

class Company
{
    public $departments;

    # Кол-во сотрудников всей компании
    public function companyEmployees(): float
    {
        $companyEmp = 0;
        foreach ($this->departments as $department) {
            $companyEmp += $department->departmentEmp();
        }
        return $companyEmp;
    }

    # Кол-во сотрудников в среднем на департамент
    public function companyEmployeesAverage(): float
    {
        return round($this->companyEmployees() / count($this->departments), 2);
    }

    #Денёжные выплаты по всей компании
    public function companySalary(): float
    {
        $companySal = 0;
        foreach ($this->departments as $department) {
            $companySal += $department->departmentSalary();
        }
        return $companySal;
    }

    # Денёжные выплаты в среднем на департамент
    public function companySalaryAverage(): float
    {
        return round($this->companySalary() / count($this->departments), 2);
    }

    # Кол-во выпитового кофе по компании
    public function companyCoffee(): float
    {
        $companyECof = 0;
        foreach ($this->departments as $department) {
            $companyECof += $department->departmentCoffee();
        }
        return $companyECof;
    }

    # Кофе в среднем на департамент
    public function companyCoffeeAverage(): float
    {
        return round($this->companyCoffee() / count($this->departments), 2);
    }

    # Кол-во страниц документов по компании
    public function companyPages(): float
    {
        $companyPag = 0;
        foreach ($this->departments as $department) {
            $companyPag += $department->departmentPages();
        }
        return $companyPag;
    }

    # Кол-во страниц в среднем на департамент
    public function companyPagesAverage(): float
    {
        return round($this->companyPages() / count($this->departments), 2);
    }

    # Сумма ден. ед. за страницу по компании
    public function companyPagePrice(): float
    {
        $companyPagPr = 0;
        foreach ($this->departments as $department) {
            $companyPagPr += $department->pagePrice();
        }
        return $companyPagPr;
    }

    # Среднея стоимость страницы по компании
    public function companyPagePriceAverage(): float
    {
        return round($this->companyPagePrice() / count($this->departments), 2);
    }
}

class Department
{
    public $name;
    public $Employees;

    #Кол-во сотрудников в отделе
    public function departmentEmp(): int
    {
        return count($this->Employees);
    }

    #Суммарные выплаты зарплат по отделу
    public function departmentSalary(): float
    {
        $departmentSalary = 0;
        foreach ($this->Employees as $employee) {
            $departmentSalary += $employee->salary();
        }
        return $departmentSalary;
    }

    #Суммарно выпитое кофе в отделе
    public function departmentCoffee(): float
    {
        $departmentCoffee = 0;
        foreach ($this->Employees as $employee) {
            $departmentCoffee += $employee->coffee();
        }
        return $departmentCoffee;
    }

    # Суммарное количество документов в отделе
    public function departmentPages(): float
    {
        $departmentPages = 0;
        foreach ($this->Employees as $employee) {
            $departmentPages += $employee->reportPages();
        }
        return $departmentPages;
    }

    # Ден. ед. за страницу по отделу
    public function pagePrice(): float
    {
        return round($this->departmentSalary() / $this->departmentPages(), 2);
    }

}

abstract class Employee
{

    public $rank; // Ранг работника
    public $isTheHead = false; // Является ли работник руководителем
    private $rankCoeff = [1, 1.25, 1.5]; // Множитель ставки в зависимости от ранга
    protected $monthlyTariffRate; // Месячная ставка
    protected $defaultCoffee; // Сколько выпивает кофе
    protected $defaultReportPages; // Сколько делает страниц документов

    public function __construct($rank, $isTheHead = false)
    {
        $this->rank = $rank;
        $this->isTheHead = $isTheHead;
    }

    # Деньги, которые получает работник
    public function salary(): float
    {
        $headCoeff = 1;
        if ($this->isTheHead) {
            $headCoeff = 1.5;
        }

        switch ($this->rank) {
            case 1:
                return $headCoeff * $this->rankCoeff[0] * $this->monthlyTariffRate;
            case 2:
                return $headCoeff * $this->rankCoeff[1] * $this->monthlyTariffRate;
            case 3:
                return $headCoeff * $this->rankCoeff[2] * $this->monthlyTariffRate;
        }
    }

    public function coffee()
    {
        if ($this->isTheHead) {
            $coffee = 0;
        } else {
            $coffee = $this->defaultCoffee;
        }
        return $coffee;
    }

    public function reportPages()
    {
        if ($this->isTheHead) {
            $reportPages = 0;
        } else {
            $reportPages = $this->defaultReportPages;
        }
        return $reportPages;
    }

}

class Manager extends Employee
{
    protected $monthlyTariffRate = 500;
    protected $defaultCoffee = 20;
    protected $defaultReportPages = 200;

}

class Marketer extends Employee
{
    protected $monthlyTariffRate = 400;
    protected $defaultCoffee = 15;
    protected $defaultReportPages = 150;

}

class Engineer extends Employee
{
    protected $monthlyTariffRate = 200;
    protected $defaultCoffee = 5;
    protected $defaultReportPages = 50;

}

class Analyst extends Employee
{
    protected $monthlyTariffRate = 800;
    protected $defaultCoffee = 50;
    protected $defaultReportPages = 5;

}


# Департамент закупок. Создание работников
# 9×ме1
$me1 = new Manager(1);
$me2 = new Manager(1);
$me3 = new Manager(1);
$me4 = new Manager(1);
$me5 = new Manager(1);
$me6 = new Manager(1);
$me7 = new Manager(1);
$me8 = new Manager(1);
$me9 = new Manager(1);

# 3×ме2
$me10 = new Manager(2);
$me11 = new Manager(2);
$me12 = new Manager(2);
#2×ме3
$me13 = new Manager(3);
$me14 = new Manager(3);

#2×ма1
$ma1 = new Marketer(1);
$ma2 = new Marketer(1);

# Руководитель департамента ме2
$me15 = new Manager(2, true);

# Массив работников для департамента закупок
$purchEmp = [$me1, $me2, $me3, $me4, $me5, $me6, $me7, $me8, $me9, $me10, $me11, $me12, $me13, $me14, $ma1, $ma2, $me15];

# Создаём отел закупок
$purchasing = new Department;
$purchasing->name = 'Закупок';
$purchasing->Employees = $purchEmp;

# Департамент продаж. Создание работников
#12×ме1
for ($i = 0; $i < 12; $i += 1) {
    $salesEmp[] = new Manager(1);
}

# 6×ма1
for ($i = 0; $i < 6; $i += 1) {
    $salesEmp[] = new Marketer(1);
}

# 3×ан1
for ($i = 0; $i < 3; $i += 1) {
    $salesEmp[] = new Analyst(1);
}

# 2×ан2
for ($i = 0; $i < 2; $i += 1) {
    $salesEmp[] = new Analyst(2);
}

#руководитель ма2
for ($i = 0; $i < 1; $i += 1) {
    $salesEmp[] = new Marketer(2, true);
}


#Создаём отдел продаж
$sales = new Department;
$sales->name = 'Продаж';
$sales->Employees = $salesEmp;

# Департамент рекламы. Создание работников
#15×ма1
for ($i = 0; $i < 15; $i += 1) {
    $advertisingEmp[] = new Manager(1);
}

#10×ма2
for ($i = 0; $i < 10; $i += 1) {
    $advertisingEmp[] = new Manager(2);
}

#8×ме1
for ($i = 0; $i < 8; $i += 1) {
    $advertisingEmp[] = new Marketer(1);
}

#2×ин1
for ($i = 0; $i < 2; $i += 1) {
    $advertisingEmp[] = new Engineer(1);
}

#руководитель ма3
for ($i = 0; $i < 1; $i += 1) {
    $advertisingEmp[] = new Manager(3, true);
}

#Создание департамента рекламы
$advertising = new Department;
$advertising->name = 'Рекламы';
$advertising->Employees = $advertisingEmp;

# Департамент логистики. Создание работников
#13×ме1
for ($i = 0; $i < 13; $i += 1) {
    $logisticsEmp[] = new Manager(1);
}

#5×ме2
for ($i = 0; $i < 5; $i += 1) {
    $logisticsEmp[] = new Manager(2);
}

#5×ин1
for ($i = 0; $i < 5; $i += 1) {
    $logisticsEmp[] = new Engineer(1);
}

#руководитель ме1
for ($i = 0; $i < 1; $i += 1) {
    $logisticsEmp[] = new Manager(1, true);
}

# Создание департамента логистики
$logistics = new Department;
$logistics->name = 'Логистики';
$logistics->Employees = $logisticsEmp;

# Все объекты департаментов кладём в массив
$departments = [$purchasing, $sales, $advertising, $logistics];

function padRight($string, int $length): string
{
    $string = (string)$string;
    $pad = $length - mb_strlen($string);
    $string = $string . str_repeat(' ', $pad);
    return $string;

}

function padLeft($string, int $length): string
{
    $string = (string)$string;
    $pad = $length - mb_strlen($string);
    $string = str_repeat(' ', $pad) . $string;
    return $string;
}


# Создание таблички
echo padRight('Департамент', 11) .
    padLeft('сотр.', 11) .
    padLeft('тугр.', 11) .
    padLeft('кофе', 11) .
    padLeft('стр.', 11) .
    padLeft('тугр./стр.', 16) .
    PHP_EOL .
    str_repeat('-', 72) .
    PHP_EOL;

foreach ($departments as $department) {
    echo padRight($department->name, 11) .
        padLeft($department->departmentEmp(), 11) .
        padLeft($department->departmentSalary(), 11) .
        padLeft($department->departmentCoffee(), 11) .
        padLeft($department->departmentPages(), 11) .
        padLeft($department->pagePrice(), 16) .
        PHP_EOL;
}

# Создаём компанию
$company1 = new Company;
$company1->departments = $departments;

# Строки 'всего', 'среднее' итоговые цифры по всей компании
echo str_repeat('-', 72) .
    PHP_EOL .
    padRight('Всего', 11) .
    padLeft($company1->companyEmployees(), 11) .
    padLeft($company1->companySalary(), 11) .
    padLeft($company1->companyCoffee(), 11) .
    padLeft($company1->companyPages(), 11) .
    padLeft('-', 16) .
    PHP_EOL;

echo padRight('Среднее', 11) .
    padLeft($company1->companyEmployeesAverage(), 11) .
    padLeft($company1->companySalaryAverage(), 11) .
    padLeft($company1->companyCoffeeAverage(), 11) .
    padLeft($company1->companyPagesAverage(), 11) .
    padLeft($company1->companyPagePriceAverage(), 16);