# -*- coding: utf-8 -*-

from sqlalchemy import create_engine
import yt.wrapper as yt
import argparse
import datetime
import logging
import os

from maps.wikimap.stat.libs.common.lib import (
    yt_helpers,
)


YT_TABLE_SCHEMA = [
    {"name": "id",          "type": "uint64", "required": True},
    {"name": "position",    "type": "any"},
    {"name": "hidden",      "type": "boolean", "required": True},
    {"name": "object_id",   "type": "uint64"},
    {"name": "description", "type": "any"},
    {"name": "source",      "type": "string", "required": True},
    {"name": "type",        "type": "string", "required": True},
    {"name": "workflow",    "type": "string", "required": True},
    {"name": "resolution",  "type": "string"},
    {"name": "commit_ids",  "type": "any"},
    {"name": "attrs",       "type": "any"},
    {"name": "fbapi_data",  "type": "any"},
    {"name": "created_at",  "type": "string", "required": True},
    {"name": "resolved_at", "type": "string"},
    {"name": "resolved_by", "type": "int64"}
]


logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(message)s'
)
logger = logging.getLogger("main-logger")

STORE_TIME_MINUTES = 60*24*7


def main():

    parser = argparse.ArgumentParser(
        description="Use environment variables 'YT_TOKEN' and 'PGPASSWORD' to pass secrets."
    )
    parser.add_argument(
        '--yt-result-table-path',
        help='Where to write dump of fbapi feedback database',
        required=True
    )
    parser.add_argument(
        '--db-user',
        help='Social database user',
        required=True
    )
    parser.add_argument(
        '--db-mdb-id',
        help='Social database in MDB',
        required=True
    )
    parser.add_argument(
        '--db-name',
        help='Social database name',
        required=True
    )

    args = parser.parse_args()

    query = """

    WITH feedback_commit_ids AS (
        -- As a result we want to have mapping: fb_id -> array[commit_id]
        -- even in case if array of commit_ids is empty, that's why
        -- we apply additional 'array_remove' to transform [null] to []
        --
        SELECT
            ft.id AS feedback_task_id,
            array_remove(array_agg(cft.commit_id), NULL) AS commit_ids
        FROM social.feedback_task ft
        LEFT JOIN social.commit_feedback_task cft
            ON ft.id = cft.feedback_task_id
        GROUP BY ft.id
    )
    SELECT
        ft.id,
        (ST_AsGeoJson(ST_Transform(position, 4326))::json)->'coordinates'
            AS position,
        ft.hidden,
        ft.object_id,
        ft.description,
        ft.source,
        ft.type,
        ft.workflow,
        ft.attrs,
        ft.resolution,
        to_json(fci.commit_ids) AS commit_ids,
        fi.raw_data AS fbapi_data,
        ft.created_at::text,
        ft.resolved_at::text,
        ft.resolved_by
    FROM social.feedback_task ft
    JOIN social.fbapi_issue fi
        ON ft.id = fi.feedback_task_id
    JOIN feedback_commit_ids fci
        ON ft.id = fci.feedback_task_id

    """

    # create yt conn
    yt_client = yt.YtClient(
        "hahn",
        token=os.environ['YT_TOKEN']
    )
    yesterday = datetime.date.today() - datetime.timedelta(days=1)
    yt_result_table = (
        args.yt_result_table_path + "/" + str(yesterday)
    )
    logger.info(
        "Writing data to YT table '{}'".format(yt_result_table)
    )

    # create db conn
    logger.info("Executing social database query")
    db_connection_string = "postgresql://{}:@{}.ro.db.yandex.net:6432/{}"\
        .format(args.db_user, args.db_mdb_id, args.db_name)
    db = create_engine(db_connection_string)

    with yt.Transaction(client=yt_client):
        yt_client.create(
            "table",
            yt_result_table,
            ignore_existing=True,
            attributes={"schema": YT_TABLE_SCHEMA}
        )

        with db.connect() as conn:
            conn = conn.execution_options(
                stream_results=True,
                isolation_level="REPEATABLE READ",
                postgresql_readonly=True
            )
            with conn.begin():
                result = conn.execute(query)
                yt_client.write_table(
                    yt_result_table,
                    map(lambda row: dict(row.items()), result.yield_per(10*1000))
                )

        yt_helpers.clear_old_tables(
            yt_client,
            args.yt_result_table_path,
            STORE_TIME_MINUTES,
            logger
        )

if __name__ == '__main__':
    main()
