/* ADCAMPAIGN-87: проактив по всем клиентам

Общая таблица с отранжированными офферами по всем клиент в читабельном человеком виде.

Назначение:
- офферы — таблица для "менеджера", без детализации, можно использоваться для 
  подсчетов на уровне клиентов
- инсайты — таблица для специалиста. Столбец `Сводка` должен содержать в себе 
  максимум полезной информации для работы над каждым конкретным клиентом.

Группа клиентов — список клиентов для проработки одним специалистом. 
Договорились использовать на старте, в будущем организовать единую на всех 
специалистов очередь. Вычисляется так: Digest::NumericHash($client_id) % 12

Обновляется ежедневно вместе с офферами по всем клиентам внутри графа Нирваны: 
https://nirvana.yandex-team.ru/flow/a7bb096d-7e6c-49df-b557-58be11890bf7.

Статистика по группам клиентов: https://yql.yandex-team.ru/Operations/XMhWzZ9LnroKhFz7vLJ4z8KGyZtylsaXOscwpPAhJhM=
*/

USE hahn;

$pprofit = ($data) -> {
  RETURN Yson::ConvertToDouble(Yson::ConvertToDict($data)["profit"]) ?? 0.;
};

$phour = ($data) -> {
  RETURN Yson::ConvertToDouble(Yson::ConvertToDict($data)["eta"]) ?? 0.;
};

$pinsight_type = ($data) -> {
  RETURN Yson::ConvertToInt64(Yson::ConvertToDict($data)["id"]) ?? 0;
};

$pfull_insight_type = ($data) -> {
  RETURN Yson::ConvertToInt64(Yson::ConvertToDict($data)["insight_type"]) ?? 0;
};

$extract_field = ($yson_list, $field_extractor) -> {
  RETURN ListMap(Yson::ConvertToList($yson_list), $field_extractor);
};

$sum_field = ($yson_list, $field_extractor) -> {
  RETURN ListSum($extract_field($yson_list, $field_extractor));
};

$crm = (
SELECT 
  client_id
, SOME(curr_manager_name) ?? "Не назначен" AS manager_name
, SOME(curr_manager_domain_login) ?? "" AS manager_login
, SOME(curr_client_tier) ?? "" AS tier
FROM `home/comdep-analytics/public/client_tiers/fact/latest`
GROUP BY client_id
);

$counterparty_crm = (
SELECT
  counterparty
, SOME(curr_manager_name) ?? "Не назначен" AS manager_name
, SOME(curr_manager_domain_login) ?? "" AS manager_login
, SOME(curr_client_tier) ?? "" AS tier
FROM `home/comdep-analytics/public/client_tiers/fact/latest`
GROUP BY curr_counterparty_name AS counterparty
);

$client_tables = (
SELECT TOP_BY(Path, CAST(TableName(Path) AS Date), 30)
FROM FOLDER(`home/comdep-cubes/direct/production/hypercubes/clients`)
);

$hypercube_stat = (
SELECT
  client_id
, SUM(cost) AS cost
FROM EACH($client_tables)
GROUP BY client_id
HAVING SUM(cost) > 100
);

$counterparty_hypercube_stat = (
SELECT
  counterparty
, SUM(h.cost) AS cost
FROM $hypercube_stat AS h
JOIN `//home/comdep-analytics/public/client_tiers/fact/latest` AS c
  ON h.client_id = c.client_id
GROUP BY c.curr_counterparty_name AS counterparty
HAVING SUM(cost) > 100
);

$activity_client_tables = (
SELECT TOP_BY(Path, CAST(TableName(Path) AS Date), 90)
FROM FOLDER(`home/comdep-cubes/direct/production/hypercubes/clients`)
);

$client_active_days = (
SELECT client_id, COUNT(*) AS active_days
FROM EACH($activity_client_tables)
WHERE cost > 0
GROUP BY client_id
);

$counterparty_active_days = (
SELECT counterparty, COUNT(DISTINCT a.cube_date) AS active_days
FROM EACH($activity_client_tables) AS a
JOIN `//home/comdep-analytics/public/client_tiers/fact/latest` AS c
  ON a.client_id = c.client_id
WHERE cost > 0
GROUP BY c.curr_counterparty_name AS counterparty
);

$client_bucket = ($client_id) -> {
  $client_id = CAST($client_id AS Uint64);
  RETURN Digest::NumericHash($client_id) % 12;
};

$counterparty_bucket = ($counterparty) -> {
  RETURN Digest::Fnv64($counterparty) % 12;
};

$translate_insight = ($key) -> {
  $INSIGHT_RU = AsDict(
    (1, "1: Быстрые ссылки и описания"),
    (2, "2: Картинки в сетях"),
    (3, "3: Уточнения"),
    (4, "4: Текущие города из запросов (путешествия)"),
    (5, "5: Текущие категории с межд. эталонами"),
    (6, "6: Текущие категории с эталонами ДО"),
  );
  RETURN $INSIGHT_RU[$key];
};

INSERT INTO `//home/vipplanners/insights/proactivity/total/offer` WITH TRUNCATE 
SELECT
  ROW_NUMBER() OVER efficiency_w AS `Ранг оффера`
, $client_bucket(ins.client_id) AS `Группа клиентов`
, ins.client_id AS `Клиент, №`
,  String::JoinFromList(
  ListMap(insight_type, ($x) -> {RETURN $translate_insight($x)}), ",\n "
) AS `Инсайты, №`
, offer_profit AS `Профит с оффера, ₽`
, offer_eta AS `Трудозатраты на оффер, ч`
, offer_profit / offer_eta AS `Профит/Ч с оффера`
, h.cost AS `Затраты клиента за 30 дней`
, c.manager_name AS `Имя менеджера`
, c.manager_login AS `Логин менеджера`
, c.tier AS `Тир клиента`
, a.active_days AS `Дней с затратами за 90 дней`
FROM (
  SELECT
    client_id
  , $extract_field(top_insight_short, $pinsight_type) AS insight_type
  , $sum_field(top_insight_short, $pprofit) AS offer_profit
  , $sum_field(top_insight_short, $phour) AS offer_eta
  FROM `//home/vipplanners/insights/pub/merged/client_id` AS in
  LEFT SEMI JOIN $crm AS wl
    ON in.client_id = wl.client_id
) AS ins
INNER JOIN $hypercube_stat AS h
  ON ins.client_id = h.client_id
LEFT JOIN $crm AS c
  ON ins.client_id = c.client_id
LEFT JOIN $client_active_days AS a
  ON ins.client_id = a.client_id
WINDOW efficiency_w AS (ORDER BY offer_profit / offer_eta DESC)
ORDER BY `Клиент, №`
;

INSERT INTO `//home/vipplanners/insights/proactivity/counterparty/total/offer` WITH TRUNCATE 
SELECT
  ROW_NUMBER() OVER efficiency_w AS `Ранг оффера`
, $counterparty_bucket(ins.counterparty) AS `Группа клиентов`
, ins.counterparty AS `Клиент`
,  String::JoinFromList(
  ListMap(insight_type, ($x) -> {RETURN $translate_insight($x)}), ",\n "
) AS `Инсайты, №`
, offer_profit AS `Профит с оффера, ₽`
, offer_eta AS `Трудозатраты на оффер, ч`
, offer_profit / offer_eta AS `Профит/Ч с оффера`
, h.cost AS `Затраты клиента за 30 дней`
, c.manager_name AS `Имя менеджера`
, c.manager_login AS `Логин менеджера`
, c.tier AS `Тир клиента`
, a.active_days AS `Дней с затратами за 90 дней`
FROM (
  SELECT
    counterparty
  , $extract_field(top_insight_short, $pinsight_type) AS insight_type
  , $sum_field(top_insight_short, $pprofit) AS offer_profit
  , $sum_field(top_insight_short, $phour) AS offer_eta
  FROM `//home/vipplanners/insights/pub/merged/counterparty` AS in
  LEFT SEMI JOIN $counterparty_crm AS wl
    ON in.counterparty = wl.counterparty
) AS ins
INNER JOIN $counterparty_hypercube_stat AS h
  ON ins.counterparty = h.counterparty
LEFT JOIN $counterparty_crm AS c
  ON ins.counterparty = c.counterparty
LEFT JOIN $counterparty_active_days AS a
  ON ins.counterparty = a.counterparty
WINDOW efficiency_w AS (ORDER BY offer_profit / offer_eta DESC)
ORDER BY `Клиент`
;


$parse_insight_short = ($insight) -> {
  RETURN AsStruct(
    $pinsight_type($insight) AS id,
    $translate_insight($pinsight_type($insight)) AS name,
    $pprofit($insight) AS profit,
    $phour($insight) AS eta);
};

$ARCPY_SRC = @@
from cyson import loads
from jinja2 import Template


def make_render(tpl):
    template = Template(tpl)
    template.globals['decode_u8'] = lambda x: x.decode("utf-8")

    def render(insight):
        if not insight:
            return None
        insight = loads(insight)

        return template.render(**insight)

    return render
@@;

PRAGMA File("1.jinja2", "yt://hahn/home/vipplanners/insights/data/template/missed_sitelinks_descriptions.jinja2");
PRAGMA File("2.jinja2", "yt://hahn/home/vipplanners/insights/data/template/missed_images.jinja2");
PRAGMA File("3.jinja2", "yt://hahn/home/vipplanners/insights/data/template/missed_callouts.jinja2");
PRAGMA File("4.jinja2", "yt://hahn/home/vipplanners/insights/data/template/missed_share_current_geocategories.jinja2");
PRAGMA File("5.jinja2", "yt://hahn/home/vipplanners/insights/data/template/missed_share_current_categories.jinja2");
PRAGMA File("6.jinja2", "yt://hahn/home/vipplanners/insights/data/template/missed_share_current_dyncategories.jinja2");

$make_ins_render = Python2::make_render(Callable< (Utf8?) -> Callable< (Yson?) -> Utf8 > >, $ARCPY_SRC);
$MAP_INSIGHTS_RENDER = AsDict(
    (1, $make_ins_render(Cast(FileContent("1.jinja2") AS Utf8))),
    (2, $make_ins_render(Cast(FileContent("2.jinja2") AS Utf8))),
    (3, $make_ins_render(Cast(FileContent("3.jinja2") AS Utf8))),
    (4, $make_ins_render(Cast(FileContent("4.jinja2") AS Utf8))),
    (5, $make_ins_render(Cast(FileContent("5.jinja2") AS Utf8))),
    (6, $make_ins_render(Cast(FileContent("6.jinja2") AS Utf8))),
);

$render_insight = ($yson_insights, $id) -> {
-- $yson_insights — оффер (список инсайтов)
-- $id — номер инсайта для рендера
  $insight = ListFilter(
      Yson::ConvertToList($yson_insights),
      ($x) -> { RETURN $pfull_insight_type($x) == $id }
  )[0];
  $render = $MAP_INSIGHTS_RENDER[$pfull_insight_type($insight)] ?? $make_ins_render("Unknown");

  RETURN $render(Yson::Serialize(Yson::ConvertToDict($insight)["data"]));
};

INSERT INTO `//home/vipplanners/insights/proactivity/total/insight` WITH TRUNCATE
SELECT
  offer_rank AS `Ранг оффера`
, $client_bucket(ins.client_id) AS `Группа клиентов`
, ins.client_id  AS `Клиент, №`
, CAST(insight_short.profit AS Int64) ?? -1 AS `Профит с инсайта, ₽`
, Math::Round(insight_short.eta, -2) AS `Трудозатраты на инсайт, ч`
, insight_short.profit / insight_short.eta AS `Профит/Ч с инсайта`
, $render_insight(top_insight_full, insight_short.id) AS `Сводка`
, insight_short.id AS `Номер инсайта`
, h.cost AS `Затраты клиента за 30 дней`
, c.manager_name AS `Имя менеджера`
, c.manager_login AS `Логин менеджера`
, c.tier AS `Тир клиента`
, offer_profit AS `Профит оффера, ₽`
, offer_eta AS `Трудозатраты на оффер, ч`
, offer_profit / offer_eta AS `Профит/Ч с оффера`
, a.active_days AS `Дней с затратами за 90 дней`
FROM (
  SELECT
    ROW_NUMBER() OVER efficiency_w AS offer_rank
  , client_id
  , top_insight_short
  , top_insight_full
  , offer_profit
  , offer_eta
  FROM (
    SELECT
      client_id
    , ListMap(Yson::ConvertToList(top_insight_short), $parse_insight_short) AS top_insight_short
    , $sum_field(top_insight_short, $pprofit) AS offer_profit
    , $sum_field(top_insight_short, $phour) AS offer_eta
    , top_insight_full
    FROM `//home/vipplanners/insights/pub/merged/client_id` AS in
    LEFT SEMI JOIN $crm AS wl
      ON in.client_id = wl.client_id
  )
  WINDOW efficiency_w AS (ORDER BY offer_profit / offer_eta DESC)
) AS ins
FLATTEN BY top_insight_short AS insight_short
INNER JOIN $hypercube_stat AS h
  ON ins.client_id = h.client_id
LEFT JOIN $crm AS c
  ON ins.client_id = c.client_id
LEFT JOIN $client_active_days AS a
  ON ins.client_id = a.client_id
ORDER BY `Клиент, №`, `Профит/Ч с инсайта` DESC
;

INSERT INTO `//home/vipplanners/insights/proactivity/counterparty/total/insight` WITH TRUNCATE
SELECT
  offer_rank AS `Ранг оффера`
, $counterparty_bucket(ins.counterparty) AS `Группа клиентов`
, ins.counterparty  AS `Клиент`
, CAST(insight_short.profit AS Int64) ?? -1 AS `Профит с инсайта, ₽`
, Math::Round(insight_short.eta, -2) AS `Трудозатраты на инсайт, ч`
, insight_short.profit / insight_short.eta AS `Профит/Ч с инсайта`
, $render_insight(top_insight_full, insight_short.id) AS `Сводка`
, insight_short.id AS `Номер инсайта`
, h.cost AS `Затраты клиента за 30 дней`
, c.manager_name AS `Имя менеджера`
, c.manager_login AS `Логин менеджера`
, c.tier AS `Тир клиента`
, offer_profit AS `Профит оффера, ₽`
, offer_eta AS `Трудозатраты на оффер, ч`
, offer_profit / offer_eta AS `Профит/Ч с оффера`
, a.active_days AS `Дней с затратами за 90 дней`
FROM (
  SELECT
    ROW_NUMBER() OVER efficiency_w AS offer_rank
  , counterparty
  , top_insight_short
  , top_insight_full
  , offer_profit
  , offer_eta
  FROM (
    SELECT
      counterparty
    , ListMap(Yson::ConvertToList(top_insight_short), $parse_insight_short) AS top_insight_short
    , $sum_field(top_insight_short, $pprofit) AS offer_profit
    , $sum_field(top_insight_short, $phour) AS offer_eta
    , top_insight_full
    FROM `//home/vipplanners/insights/pub/merged/counterparty` AS in
    LEFT SEMI JOIN $counterparty_crm AS wl
      ON in.counterparty = wl.counterparty
  )
  WINDOW efficiency_w AS (ORDER BY offer_profit / offer_eta DESC)
) AS ins
FLATTEN BY top_insight_short AS insight_short
INNER JOIN $counterparty_hypercube_stat AS h
  ON ins.counterparty = h.counterparty
LEFT JOIN $counterparty_crm AS c
  ON ins.counterparty = c.counterparty
LEFT JOIN $counterparty_active_days AS a
  ON ins.counterparty = a.counterparty
ORDER BY `Клиент`, `Профит/Ч с инсайта` DESC
;
