from functools import partial

from polecat.db.query import query as query_module
from psycopg2.sql import SQL, Placeholder

from .expression import Expression


class Values(Expression):
    def __init__(self, values, relation=None):
        self.values = values
        self.relation = relation
        self.keyword = 'VALUES'

    def to_sql(self):
        if isinstance(self.values, query_module.Values):
            get_values_sql = partial(
                self.get_values_sql_from_values, self.values
            )
        else:
            get_values_sql = partial(
                self.get_values_sql_from_dict, self.values
            )
        return self.get_values_sql(get_values_sql)

    def get_values_sql(self, get_values_sql):
        values_sql, values_args = get_values_sql()
        joined_sql = SQL(', ').join(
            SQL('({})').format(
                SQL(', ').join(row_sql)
            )
            for row_sql in values_sql
        )
        return SQL('%s {}' % self.keyword).format(joined_sql), values_args

    def get_values_sql_from_values(self, values):
        column_values_sql = []
        column_values = ()
        for row in values.iter_rows():
            row_values_sql = []
            for column_name, column_value in row:
                value_sql, value = self.value_to_sql(column_value, column_name)
                row_values_sql.append(value_sql)
                column_values += value
            column_values_sql.append(row_values_sql)
        return column_values_sql, column_values

    def get_values_sql_from_dict(self, values_dict):
        column_values_sql = []
        column_values = ()
        for column_name, column_value in values_dict.items():
            value_sql, value = self.value_to_sql(column_value, column_name)
            column_values_sql.append(value_sql)
            column_values += value
        return (column_values_sql,), column_values

    def value_to_sql(self, value, column_name=None):
        if isinstance(value, Expression):
            sql, args = value.to_sql()
            return SQL('{}').format(sql), args
        else:
            if self.relation and column_name:
                column = self.relation.get_column(column_name)
                value = column.to_db_value(value)
            return Placeholder(), (value,)

    def iter_column_names(self):
        if isinstance(self.values, dict):
            return self.values.keys()
        else:
            return self.values.iter_column_names()

[((17, 29, 19, 13), 'functools.partial', 'partial', ({(18, 16, 18, 47): 'self.get_values_sql_from_values', (18, 49, 18, 60): 'self.values'}, {}), '(self.get_values_sql_from_values, self.values)', False, 'from functools import partial\n'), ((21, 29, 23, 13), 'functools.partial', 'partial', ({(22, 16, 22, 45): 'self.get_values_sql_from_dict', (22, 47, 22, 58): 'self.values'}, {}), '(self.get_values_sql_from_dict, self.values)', False, 'from functools import partial\n'), ((28, 21, 28, 30), 'psycopg2.sql.SQL', 'SQL', ({(28, 25, 28, 29): '""", """'}, {}), "(', ')", False, 'from psycopg2.sql import SQL, Placeholder\n'), ((65, 19, 65, 32), 'psycopg2.sql.Placeholder', 'Placeholder', ({}, {}), '()', False, 'from psycopg2.sql import SQL, Placeholder\n'), ((34, 15, 34, 42), 'psycopg2.sql.SQL', 'SQL', ({(34, 19, 34, 41): "('%s {}' % self.keyword)"}, {}), "('%s {}' % self.keyword)", False, 'from psycopg2.sql import SQL, Placeholder\n'), ((29, 12, 29, 23), 'psycopg2.sql.SQL', 'SQL', ({(29, 16, 29, 22): '"""({})"""'}, {}), "('({})')", False, 'from psycopg2.sql import SQL, Placeholder\n'), ((60, 19, 60, 28), 'psycopg2.sql.SQL', 'SQL', ({(60, 23, 60, 27): '"""{}"""'}, {}), "('{}')", False, 'from psycopg2.sql import SQL, Placeholder\n'), ((30, 16, 30, 25), 'psycopg2.sql.SQL', 'SQL', ({(30, 20, 30, 24): '""", """'}, {}), "(', ')", False, 'from psycopg2.sql import SQL, Placeholder\n')]