import { DropdownField } from "cmp/dropdownField/DropdownField.jsx";
import { PlainSelect } from "cmp/PlainSelect/PlainSelect.jsx";
import { Checkbox } from "cmp/Checkbox/Checkbox.jsx";
import { Radio } from "cmp/Radio/Radio.jsx";
import {Info, Content, Note, Header, SubHeader, Field} from '/cmp/Blocks.jsx';
import './VideoCalculator.scss';

var months = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'Jule',
  'August',
  'September',
  'October',
  'November',
  'December'
];
var monthsShort = [
  'Jan',
  'Feb',
  'Mar',
  'Apr',
  'May',
  'Jun',
  'Jul',
  'Aug',
  'Sept',
  'Oct',
  'Nov',
  'Dec'
];
var {
  size,
  codec,
  framerate,
  time,

  filesize,
  filesize2,
  filesize3,
  perDay,
  simult,
  popularity,
  creating,
  useInterlacing,
  calculation,
  backups,
  duration,
  dc,
  viewersFrom,
  viewersTo
} = s.bindings();
var AWSStorePrice = function(gb) {
  if(gb<1024*50)
    return 0.023;

  if(gb<1024*450)
    return 0.022;


  return 0.021;
};
var AWSTransferPrice = function(gb) {
  var sum = 0, pack;
  pack = Math.min(gb, 9.999*1024);
  sum += pack*0.09;
  gb -= pack;
  if(gb<=0.0001){
    return sum;
  }

  pack = Math.min(gb, 40*1024);
  sum += pack*0.085;
  gb -= pack;
  if(gb<=0.0001){
    return sum;
  }

  pack = Math.min(gb, 100*1024);
  sum += pack*0.07;
  gb -= pack;
  if(gb<=0.0001){
    return sum;
  }
  sum += gb*0.05;
  return sum;
};
var moneyFormatter = function(num) {
  var strNum = num+'';
  var i,
    out = [],
    _i = strNum.length,
    count = (_i%3)||3,
    last = count;

  out.push(strNum.substr(0, count));
  count = 3;
  for(i = last; i < _i; i+=3){
    out.push(strNum.substr(i, count))
  }
  return out.join(',');
};
var GBFormatter = function(gb) {
  if(gb-0 < 1024){
    return (gb-0).toFixed(2)+'GB';
  }
  gb/=1024;
  if(gb-0 < 1024){
    return (gb-0).toFixed(2)+'TB';
  }
  gb/=1024;
  //if(gb-0 < 1024){
    return (gb-0).toFixed(2)+'PB';
  //}
};
var sizeSelector;

var VideoCalculator = <div class={'calculator'}>
  <Header>
    Видеосервис
  </Header>
  <Content>
    <p>
      Хранение и передача видео в реальном времени — сложная и ресурсоёмкая задача с точки зрения инфраструктуры.
    </p>
    <p>
      Рассмотрим процесс от загрузки видеофайла создателем контента до проигрывания у конечного пользователя:
    </p><p>
      <ol>
        <li><i>Видео</i> снято, смонтировано и <i>готово к загрузке</i> в нашу систему.</li>
        <li>Выбираем видео в списке файлов и <i>начинаем загрузку</i>. Это значит что наша <i>система имеет достаточно места</i> для хранения данных. YouTube позволяет загружать файлы до 128GB.</li>
        <li><i>Дисконнект</i>. До окончания загрузки осталось 6 часов, 3 часа уже прошло. YouTube в таком случае позволяет продолжить загрузку файла с контрольной точки. Это не стандартное поведение браузера и файлсервера. Такое решение требует отдельной разработки. Многие сервисы в таком случае предлагают начать процесс загрузки с начала.</li>
        <li><i>Перекодирование</i>. Загрузка завершена! Теперь будем перекодировать файл в подходящие для браузеров и smartTV форматы. Перекодирование — это длительный и ресурсоёмкий процесс. Этот процесс хорошо распараллеливается, а значит его можно ускорить за счёт увеличения количества процессоров и ядер на серверах занимающихся перекодированием. Сейчас, в 2020 году, процесс перекодирования FullHD в 720p <a href="https://www.guru3d.com/articles-pages/intel-core-i9-9900k-processor-review,14.html" target="_blank">всё ещё занимает</a> время равное длительности загружаемое видео. Система должна одновременно перекодировать множество видео в большое количество форматов.
        </li>
        <li>
          <p>
          <i>Очередь задач</i> и <i>масштабирование</i>. Для общения частей системы выполняющих разные роли построим единую шину данных в которую будут добавляться новые задачи. Сервисы способные выполнить задачу будут забирать её из очереди и заниматься ей. Если очередь растёт быстрее чем задачи успевают обрабатываться — мы можем <i>моментально масштабировать инфраструктуру</i> путём добавления вычислительных узлов аналогичных загруженным.
          </p><p>
          Перекодирование в 144p занимает на порядки меньше времени чем перекодирование в 1080p и если издателю важно выложить контент как можно скорее — он может быть удовлетворён и таким стартом.
          </p>
        </li>
        <li>
          <p>
          <i>Публикация</i> и <i>доставка</i> на устройство пользователя. Видео выложено в публичный доступ. С этого момента мы <i>отслеживаем геолокацию зрителей</i>.
          </p>
          <p>
            Для экономии средств на передаче траффика и ускорения загрузки видео мы должны осуществлять доставку с серверов находящихся как можно ближе к зрителям. Можно построить свой <i>Content Delivery Network</i>, но оптимально будет воспользоваться готовыми. Как правило они дают всё необходимое для загрузки файлов и <i>балансировки нагрузки</i>.
          </p>
        </li>
      </ol>
  </p>
  <p>
    Каждая из описаных выше систем (перекодировка, дозагрузка, очередь задач, CDN, балансировщик) способна занять годы разработки, отладки и внедрения и не гарантирует что на выходе получится работоспособный результат. По этой причине мы настоятельно рекомендуем собрать прототип из наиболее стабильных общедоступных решений. После начального роста можно будет рассмотреть процесс замены дорогих сервисов на своими.
  </p>
  </Content>

  <Note>
    Интерактивный калькулятор покажет из каких величин складывается стоимость хранения и передачи видеоконтента. Все поля ввода можно изменять. Результаты расчётов обновляются в реальном времени.
  </Note>

  <Header>
    Хранение и передача видео
  </Header>
  <SubHeader>
    Размера видеофайла
  </SubHeader>

  <div class={'field'}><label>Разрешение видео {sizeSelector = <PlainSelect value={size} map={(val)=>({w: val.split('x')[0]-0, h: val.split('x')[1]-0})} values={`
    256x144
    426x240
    640x360
    854x480
    >1280x720
    1920x1080
    2560x1440
    3840x2160
    7680x4320
  `}/>}</label></div>
  {_=>{
    sizeSelector.values.get().forEach(item=> {
      s.set( 'use-' + item.id.split( 'x' )[ 1 ], true );
    })
  }}
  <div class={'field'}><label>Используемый кодек <PlainSelect value={codec} map={Number} values={`
    180: H.264 High quality
    >340: H.264 Medium quality
    675: H.264 Low quality
  `}/></label></div>

  <div className={'field'}><label>Кадров в секунду <PlainSelect value={framerate} map={Number} values={`
    24
    30
    >60
    120
    240
  `}/></label></div>


  <div className={'field'}><label>Продолжительность серии <PlainSelect value={time} map={Number} values={`
    15: 15 минут
    >30: 30 минут
    60: 1 час
    120: 2 часа
    135: 2 часа 15 минут
    210: 3 часа 30 минут
  `}/></label></div>


  {_=>s.sub([size, codec, framerate, time], (size, codec, framerate, time)=>{
    var [w,h] = size.split('x');
    filesize.set((w*h*3/codec*framerate*time*60 / 1024 / 1024 / 1024).toFixed(2));
  })}


  <div className={'field'}>Размер видеофайла: {_=>s.sub([filesize],(filesize)=>_(GBFormatter(filesize)))}</div>

  <SubHeader>
    Интерлейсинг
  </SubHeader>

  <Content>
    Технология интерлейсинга или <i>чересстрочная развёртка</i> экономит половину места при хранении и передаче видеофайлов. Вместо полного кадра, пеередаются чётные и нечётные строки поочерёдно. Технологии распространилась из-за физических ограничений накладываемых принципами работы Электронно-Лучевой трубки. Мы тоже можем извлечь выгоду из этого метода, но не рекомендуем.
  </Content>

  <img src="https://blog.video.ibm.com/wp-content/uploads/2016/03/interlace-soccer2-1024x394.jpg" style="display: block;margin: auto;"/>



  <div className={'field'}><label><Checkbox value={useInterlacing}/> Использовать интерлэйсинг</label></div>

  {_=>s.sub([useInterlacing, filesize], (useInterlacing, filesize)=>{
    filesize2.set(useInterlacing ? filesize/2 : filesize);
  })}

  {_=>s.sub([size, codec, framerate, time, 'filesize3', useInterlacing,
    'use-144', 'use-240', 'use-360', 'use-480', 'use-720', 'use-1080', 'use-1440', 'use-2160', 'use-4320'], (size, codec, framerate, time, filesize3, useInterlacing)=>{
    var downscales = [],
        vals = sizeSelector.values.get();
    for( var i = 0, _i = vals.length; i < _i; i++ ){
      var [w,h] = vals[ i ].text.split('x');

      downscales.push({p: h, size: (w*h*3/codec*framerate*time*60 / 1024 / 1024 / 1024).toFixed(2)});

      if(vals[ i ].id === size){
        break;
      }
    }

    if(downscales.length>1){

      s.set('filesize3', (downscales.map(item=>s.get('use-'+item.p)?item.size-0:0).reduce((a,b)=>a+b)  * (useInterlacing ? 0.5 : 1)).toFixed(2));

      _(<div><SubHeader hidden={true}>Объём занимаемый различными форматами</SubHeader>
        <Content>Для хранения всех разрешений видео требуется в среднем в два раза больше места чем занимает видео в самом высоком разрешении. Форматы которые не нравятся можно выключить.</Content>

        <table>
            <tr class={'thead'}>
              <td></td>
              <td>Формат</td>
              <td>Объём</td>
            </tr>
            {downscales.map(item=><tr>
              <td><Checkbox value={s.bind('use-'+item.p)}/></td>
              <td>{item.p}p</td>
              <td>{GBFormatter(item.size * (useInterlacing ? 0.5 : 1))}</td>
            </tr>)}
            <tr class={'summary'}>
              <td colSpan={3}>
                Всего <b>{GBFormatter(s.get('filesize3'))}</b> на серию
              </td>
            </tr>
        </table>


      </div>);

      console.log(s.get('filesize3'));
    }else{
      s.set('filesize3',  (downscales[0].size * (useInterlacing ? 0.5 : 1)).toFixed(2));
      _(<div>Объём необходимый для хранения одного выпуска — {GBFormatter(s.get('filesize3'))}</div>);
    }

  })}
  <SubHeader>Выбор типа расчёта</SubHeader>
  <Content>
    <p>Видеоплатформы делятся на два типа — в одни контент загружают издатели (HBO, Netflix), а в другие — пользователи (YouTube, Vimeo, Pornhub). В нашем случае будет разработана смесь обоих подходов.</p>
  </Content>
  <Field label='Сериальный расчёт'><Radio value='tv-show' group={calculation}/></Field>
  <Field label='Видеоплатформенный расчёт'><Radio value='ott' group={calculation}/></Field>

  {_=>{
    calculation.sub(val=>{
      if(val === 'tv-show'){
        _(<div>
          <Header hidden={true}>Сериальный расчёт</Header>
          <SubHeader hidden={true}>Количество и частота выходящих серий</SubHeader>
          <Content>При сериальном расчёте занимаемый объём данных можно легко прогнозировать на полгода вперёд.</Content>
          <div className={'field'}><label>Одновременно выходят <PlainSelect value={simult} map={Number} values={`
            1: Одно шоу
            2: Два шоу
            >5: Пять шоу
            10: Десять шоу
            50: Сорок шоу, некоторые разветвились и получлось 50
            100: Шоу, челленджи, платформа популярна, но не на весь мир
          `}/></label></div>

          <div class={'field'}><label>Новая серия выходит <PlainSelect value={perDay} map={Number} values={`
            1: Каждый день
            >7: Каждую неделю
            30: Каждый месяц
            28: Сезон из 13 серий USA\Canada standard
            16.5: Сезон из 22 серий USA\Canada standard
          `}/></label></div>
        </div>);
      }else if(val === 'ott'){
        _(<div>
          <Header hidden={true}>Расчёт для видеоплатформы</Header>
          <Info>На основе <a href="https://merchdope.com/youtube-stats/#:~:text=The%20total%20number%20of%20people,on%20Youtube%20every%20single%20day.&text=In%20an%20average%20month%2C%208,49%20year%2Dolds%20watch%20YouTube" target='_blank'>статистики по ютубу за 2020 год</a> и
             доступных публичных данных <a href="https://www.similarweb.com/top-websites" target="_blank">от similarweb</a> были выстроены примерные оценки нагрузки на хранилища файлов для различных видеосервисов.
          </Info>
          <Field label={'Популярность'}>
            <PlainSelect value={popularity} map={Number} values={`
              300: YouTube. 300 hours of video uploaded every minute. Traffic: 33.39B
              25: Pornhub. 25 hours of video uploaded every minute (scaled). Traffic: 2.85B
              1.19: Vimeo. 1.19 hours of video uploaded every minute (scaled). Traffic: 133.7M
              0.1: Traffic: 10M Good globally known platform. 8 minutes of video per minute
              0.0125: Traffic: 1M. Good local OTT platform. 1 minute of video per minute
              >0.002: Netflix 90000 minutes of original video in 2018 year
            `}/>
          </Field>

        </div>);
      }
    })
  }}



  <SubHeader>Расчёт требуемого для хранения данных места</SubHeader>

  <p>
    Для упрощения — будем считать что количество контента и зрителей нарастает линейно.
  </p>

  <Field label={'Временной промежуток'}>
    <PlainSelect value={duration} map={Number} values={`
      1:1 month
      12: 1 year
      >24: 2 year
      36: 3 year
      48: 4 year
      60: 5 year
    `}/>
  </Field>

  <p>

  </p>

  <Content>
    <p>
      На первых этапах (демонстрация, первые 6 месяцев) можно раздавать контент с одного сервера.
    </p>
    <p>
      Далее можно взять несколько серверов в оптимальных местах (европа, северная и южная америка, азия, западная и восточная Россия).
    </p>
    <p>
      При серьёзном масштабировании OTT платформы нужно будет обязательно выбрать подходящее CDN решение или построить своё.
    </p>
    <p>
      CDN позволяет как экономить международный траффик между клиентом и сервером раздающим видео, так и снять нагрузку с ключевых элементов инфраструктуры.
    </p>
    <p>
      Много пользователей из Америки одновременно смотрящих премьеру передачи с европейского сервера способны существенно забить трансокеанические кабели передачи данных, или, сделать всю затею нерентабельной.
    </p>

  </Content>
  <Field label={'Датацентры'} width={250}>
    <PlainSelect value={dc} map={Number} values={`
      0: Не нужен
      >2: Разворачиваем 3 своих датацентров
      5: Разворачиваем 6 своих датацентров
    `}/>
  </Field>


  <Field label={'Хранение бэкапов'}  width={250}>
    <PlainSelect value={backups} map={Number} values={`
      0: Мы не храним бэкапов!
      1: RAID 10. Дублирование всех записанных данных
      >0.3: RAID 3. Отдельный диск для битов чётности. Минимум 4 диска
      2: Кворум из трёх машин. Обычно используется для финансовых БД
    `}/>
  </Field>

  <Content>
    <p>
      На больших объёмах основными потребителями ежемесячного бюджета становятся сервера и оплата траффика. Траффик напрямую зависит от количества пользователей платформы.
    </p>
    <p>
      Пользователь Netfilx в среднем проводит 2 часа в день за просмотром контента Netflix. В дальнейших вычислениях потребляемого траффика будем считать что пользователь смотрит в день один час видео в самом популярном формате 720p.
    </p>
  </Content>

  <Field label={'Пользователей в месяц в начале'} width={350}>
    <PlainSelect value={viewersFrom} map={Number} values={`
      0: Нет пользователей 
      >20: 20 — Тестирование платформы 
      500: 500 — Ранний запуск
      4000: 4000 — Набирает популярность
      10000: 10000 — Набирает популярность
      
      180000000: 180 000 000 — Аудитория Netflix
    `}/>
  </Field>

  <Field label={'Пользователей в месяц в конце'} width={350}>
    <PlainSelect value={viewersTo} map={Number} values={`
      0: Нет пользователей 
      20: 20 — Тестирование платформы 
      500: 500 — Ранний запуск
      >4000: 4000 — Набирает популярность
      10000: 10000 — Набирает популярность
      
      180000000: 180 000 000 — Аудитория Netflix
    `}/>
  </Field>



  <SubHeader>Результат для AWS</SubHeader>
  <p>Данные в таблице отражают только объём и траффик потребляемый для хранения\передачи видео с разбивкой на месяцы. Внутреннее потребление на хранение оригиналов видеофайлов может оказаться даже выше расчётного если к проекту подключатся киностудии и начнут загружать оригинальный или Blu Ray формат</p>
  <p>Цена стоимости траффика <a href="https://aws.amazon.com/mediastore/pricing/">вычисляется по данным с официального сайта AWS</a>.</p>
  {_=>{
    s.sub([


      duration,
      backups,
      calculation,

      simult, perDay,
      popularity,
      time,
      filesize3, dc,
      viewersFrom,
      viewersTo, codec, framerate
    ], (

      duration,
      backups,
      calculation,

      simult, perDay,
      popularity, time,
      filesize3, dc,
      viewersFrom,
      viewersTo, codec, framerate
    )=>{

      var origDate = +new Date(),
          d = origDate,
          lastDate = d,
          slices = [],
          stored = 0;
      viewersTo|=0;
      viewersFrom|=0;
      var deltaViewers = (viewersTo-viewersFrom)/(duration-1);
      for(var i = 0; i < duration; i++){
        d = new Date(d);
        d.setMonth(d.getMonth()+1);

        var slice = {date: d},
            newData;
        if(calculation === 'ott'){
          newData =
            (filesize3/time)* // minute size
            (((+d)-(+lastDate))/1000/60)* // minutes in month
            popularity*60;
        }else{
          newData = filesize3*simult*(((+d)-(+lastDate))/1000/60/60/24 / perDay)
        }
        newData+=newData*backups;
        newData+=newData*dc;
        stored += newData;
        slice.stored = stored;
        slice.newData = newData;
        slice.users = (viewersFrom + deltaViewers*i)|0;

        slice.traffic = slice.users * (((+d) - (+lastDate))/24/1000)*(1280*720*3/codec*framerate)/1024/1024/1024;

        lastDate = d;
        slices.push(slice);
      }

      _(<table>
        <tr className={'thead'}>
          <td>Дата</td>
          <td>Объём</td>
          <td>AWS Storage</td>

          <td>Пользователей</td>
          <td>Traffic Amount</td>
          <td>AWS Traffic Price</td>
        </tr>
        {slices.map(slice=><tr>
          <td>{monthsShort[slice.date.getMonth()] +' '+ slice.date.getFullYear()}</td>
          <td>{GBFormatter(slice.stored)}</td>
          <td>${moneyFormatter((slice.stored*AWSStorePrice(slice.stored))|0)}/month</td>
          <td>{moneyFormatter(slice.users)}</td>
          <td>{GBFormatter(slice.traffic)}/month</td>
          <td>${moneyFormatter((AWSTransferPrice(slice.traffic))|0)}/month</td>
        </tr>)}
      </table>);



    });
  }}

  <Content>
    <p>Netflix использует для перекодирования и хранения видео Amazon AWS, а для раздачи — сразу несколько CDN провайдеров</p>
    <p><img src="amazon-structure.png" alt="amazon structure"/></p>

    <a href="https://medium.com/refraction-tech-everything/how-netflix-works-the-hugely-simplified-complex-stuff-that-happens-every-time-you-hit-play-3a40c9be254b" target="_blank">
      Здесь можно почитать о том как строится инфраструктура подобная Netflix
    </a>
  </Content>


  USE: https://www.wowza.com/products/streaming-engine/deployment-options

  <h1>TODO: Дополнить варианты реализации чтоб был выбор из трёх стульев</h1>

</div>;

export {VideoCalculator};