from .base import list_biz_clients_subq

events_stat_cte = f"""
order_events_stat AS (
    SELECT client_id,
        biz_id,
        count(orders.id) AS total_orders_count,
        count(*) FILTER (
            WHERE orders.event_type='CREATED'
        ) AS total_orders_created_count,
        count(*) FILTER (
            WHERE orders.event_type='REJECTED'
        ) AS total_orders_rejected_count,
        count(*) FILTER (
            WHERE orders.event_type='ACCEPTED'
        ) AS total_orders_accepted_count,
        count(*) FILTER (
            WHERE orders.event_type='CREATED'
                AND orders.event_timestamp >= $2
        ) AS recent_orders_created_count,
        count(*) FILTER (
            WHERE orders.event_type='REJECTED'
                AND orders.event_timestamp >= $2
        ) AS recent_orders_rejected_count,
        count(*) FILTER (
            WHERE orders.event_type='ACCEPTED'
                AND orders.event_timestamp >= $2
        ) AS recent_orders_accepted_count,
        max(orders.event_timestamp) FILTER (
            WHERE orders.event_type='CREATED'
        ) AS last_order_created_ts
    FROM ({list_biz_clients_subq}) AS bc
    LEFT JOIN order_events as orders USING (client_id, biz_id)
    GROUP BY client_id, biz_id
),
call_events_stat AS (
    SELECT client_id,
        biz_id,
        count(call_events.id) AS total_calls_count,
        count(*) FILTER (
            WHERE call_events.event_timestamp >= $2
        ) AS recent_calls_count
    FROM ({list_biz_clients_subq}) AS bc
    LEFT JOIN call_events USING (client_id, biz_id)
    GROUP BY client_id, biz_id
),
events_stat AS (
    SELECT
        os.*,
        os.total_orders_count + cs.total_calls_count AS total_count,
        cs.recent_calls_count
    FROM order_events_stat AS os
    JOIN call_events_stat AS cs USING (client_id, biz_id)
)
"""

regular_segment_cte = """
regular_clients AS (
    SELECT client_id
    FROM events_stat
    WHERE recent_orders_created_count > 2
)
"""

active_segment_cte = """
active_clients AS (
    SELECT client_id
    FROM events_stat
    WHERE recent_orders_accepted_count + recent_calls_count > 0
)
"""

lost_segment_cte = """
lost_clients AS (
    SELECT client_id
    FROM events_stat
    WHERE total_count > 0
        AND recent_calls_count = 0
        AND (
            recent_orders_created_count = 0
            OR recent_orders_created_count = recent_orders_rejected_count
        )
)
"""

unprocessed_segment_cte = """
unprocessed_orders_clients AS (
    SELECT client_id
    FROM events_stat
    WHERE total_orders_created_count > 0
        AND total_orders_created_count > total_orders_rejected_count + total_orders_accepted_count
)
"""  # noqa

no_orders_segment_cte = """
no_orders_clients AS (
    SELECT client_id
    FROM events_stat
    WHERE total_orders_count=0
)
"""

short_last_call_segment_cte = f"""
short_last_call_clients AS (
    SELECT client_id
    FROM (
        SELECT DISTINCT ON (client_id) client_id, event_type, event_value, talk_duration
        FROM call_events
        WHERE client_id IN (
            SELECT client_id
            FROM ({list_biz_clients_subq}) AS _bc
        )
        ORDER BY client_id, event_timestamp DESC, created_at DESC
    ) _last_calls
    WHERE _last_calls.event_type = 'FINISHED'
        AND _last_calls.talk_duration BETWEEN 1 AND 9
)
"""

missed_last_call_segment_cte = f"""
missed_last_call_clients AS (
    SELECT client_id
    FROM (
        SELECT DISTINCT ON (client_id) client_id, event_type, talk_duration
        FROM call_events
        WHERE client_id IN (
            SELECT client_id
            FROM ({list_biz_clients_subq}) AS _bc
        )
        ORDER BY client_id, event_timestamp DESC, created_at DESC
    ) _last_calls
    WHERE _last_calls.event_type = 'FINISHED'
        AND _last_calls.talk_duration = 0
)
"""

segments_ctes = ", ".join(
    [
        events_stat_cte,
        regular_segment_cte,
        active_segment_cte,
        lost_segment_cte,
        unprocessed_segment_cte,
        no_orders_segment_cte,
        short_last_call_segment_cte,
        missed_last_call_segment_cte,
    ]
)

clients_with_segments_cte = f"""
{segments_ctes},
    clients_with_segments AS (
    SELECT *, array_remove(
        ARRAY[
            CASE WHEN in_regular_segment THEN 'REGULAR' END,
            CASE WHEN in_active_segment THEN 'ACTIVE' END,
            CASE WHEN in_lost_segment THEN 'LOST' END,
            CASE WHEN in_unprocessed_orders_segment THEN 'UNPROCESSED_ORDERS' END,
            CASE WHEN in_no_orders_segment THEN 'NO_ORDERS' END,
            CASE WHEN in_short_last_call_segment THEN 'SHORT_LAST_CALL' END,
            CASE WHEN in_missed_last_call_segment THEN 'MISSED_LAST_CALL' END
        ], NULL
    ) AS segments
    FROM (
        SELECT c.*,
            rc.client_id IS NOT NULL AS in_regular_segment,
            ac.client_id IS NOT NULL AS in_active_segment,
            lc.client_id IS NOT NULL AS in_lost_segment,
            uoc.client_id IS NOT NULL AS in_unprocessed_orders_segment,
            noc.client_id IS NOT NULL AS in_no_orders_segment,
            scc.client_id IS NOT NULL AS in_short_last_call_segment,
            mcc.client_id IS NOT NULL AS in_missed_last_call_segment
        FROM ({list_biz_clients_subq}) AS c
        LEFT JOIN regular_clients AS rc USING (client_id)
        LEFT JOIN active_clients AS ac USING (client_id)
        LEFT JOIN lost_clients AS lc USING(client_id)
        LEFT JOIN unprocessed_orders_clients AS uoc USING(client_id)
        LEFT JOIN no_orders_clients AS noc USING(client_id)
        LEFT JOIN short_last_call_clients AS scc USING(client_id)
        LEFT JOIN missed_last_call_clients AS mcc USING(client_id)
    ) _fbs
)
"""

list_segments = """
WITH
events_stat AS (
    SELECT
        clients.id,
        clients.created_at AS client_created_at,
        count(orders.id) + count(calls.id) AS total_count_current,
        count(orders.id) FILTER ( WHERE orders.event_timestamp < $4 )
            + count(calls.id)  FILTER ( WHERE calls.event_timestamp < $4 )
            AS total_count_previous,
        count(orders.id) AS total_orders_count_current,
        count(orders.id) FILTER ( WHERE calls.event_timestamp < $4 )
            AS total_orders_count_previous,
        count(*) FILTER (
            WHERE orders.event_type='CREATED'
        ) AS total_orders_created_count_current,
        count(*) FILTER (
            WHERE orders.event_type='CREATED' AND orders.event_timestamp < $4
        ) AS total_orders_created_count_previous,
        count(*) FILTER (
            WHERE orders.event_type='REJECTED'
        ) AS total_orders_rejected_count_current,
        count(*) FILTER (
            WHERE orders.event_type='ACCEPTED'
        ) AS total_orders_accepted_count_current,
        count(*) FILTER (
            WHERE orders.event_type='REJECTED' AND orders.event_timestamp < $4
        ) AS total_orders_rejected_count_previous,
        count(*) FILTER (
            WHERE orders.event_type='ACCEPTED' AND orders.event_timestamp < $4
        ) AS total_orders_accepted_count_previous,
        count(*) FILTER (
            WHERE calls.event_timestamp >= $2
        ) AS recent_calls_count_current,
        count(*) FILTER (
            WHERE calls.event_timestamp BETWEEN $3 AND $4
        ) AS recent_calls_count_previous,
        count(*) FILTER (
            WHERE orders.event_type='CREATED'
                AND orders.event_timestamp >= $2
        ) AS recent_orders_created_count_current,
        count(*) FILTER (
            WHERE orders.event_type='CREATED'
                AND orders.event_timestamp BETWEEN $3 AND $4
        ) AS recent_orders_created_count_previous,
        count(*) FILTER (
            WHERE orders.event_type='REJECTED'
                AND orders.event_timestamp >= $2
        ) AS recent_orders_rejected_count_current,
        count(*) FILTER (
            WHERE orders.event_type='REJECTED'
                AND orders.event_timestamp BETWEEN $3 AND $4
        ) AS recent_orders_rejected_count_previous,
        count(*) FILTER (
            WHERE orders.event_type='ACCEPTED'
                AND orders.event_timestamp >= $2
        ) AS recent_orders_accepted_count_current,
        count(*) FILTER (
            WHERE orders.event_type='ACCEPTED'
                AND orders.event_timestamp BETWEEN $3 AND $4
        ) AS recent_orders_accepted_count_previous,
        max(orders.event_timestamp) FILTER (
            WHERE orders.event_type='CREATED'
        ) AS last_order_created_ts,
        (array_agg(calls.event_type ORDER BY calls.event_timestamp DESC))[1]
            AS last_call_event_type_current,
        (array_agg(calls.talk_duration ORDER BY calls.event_timestamp DESC))[1]
            AS last_call_talk_duration_current,
        (array_agg(calls.event_type ORDER BY calls.event_timestamp DESC) FILTER (
            WHERE calls.event_timestamp < $4
        ))[1] AS last_call_event_type_previous,
        (array_agg(calls.talk_duration ORDER BY calls.event_timestamp DESC) FILTER (
            WHERE calls.event_timestamp < $4
        ))[1] AS last_call_talk_duration_previous
    FROM clients
    LEFT JOIN order_events as orders ON clients.id = orders.client_id
    LEFT JOIN call_events as calls ON clients.id = calls.client_id
    WHERE clients.biz_id = $1
    GROUP BY clients.id
),
segments_sizes AS (
    SELECT
        COUNT(*) FILTER ( WHERE recent_orders_created_count_current > 2 )
            AS regular_count_current,
        COUNT(*) FILTER ( WHERE recent_orders_created_count_previous > 2 )
            AS regular_count_previous,
        COUNT(*) FILTER (
            WHERE recent_orders_accepted_count_current + recent_calls_count_current > 0
        ) AS active_count_current,
        COUNT(*) FILTER (
            WHERE recent_orders_accepted_count_previous + recent_calls_count_previous > 0
        ) AS active_count_previous,
        COUNT(*) FILTER (
            WHERE total_count_current > 0
                AND recent_calls_count_current = 0
                AND (
                    recent_orders_created_count_current = 0
                    OR recent_orders_created_count_current = recent_orders_rejected_count_current
                )
        ) AS lost_count_current,
        COUNT(*) FILTER (
            WHERE total_count_previous > 0
                AND recent_calls_count_previous = 0
                AND (
                    recent_orders_created_count_previous = 0
                    OR recent_orders_created_count_previous = recent_orders_rejected_count_previous
                )
        ) AS lost_count_previous,
        COUNT(*) FILTER (
            WHERE total_orders_created_count_current > 0
                AND total_orders_created_count_current >
                    total_orders_rejected_count_current + total_orders_accepted_count_current
        ) AS unprocessed_orders_count_current,
        COUNT(*) FILTER (
            WHERE total_orders_created_count_previous > 0
                AND total_orders_created_count_previous >
                    total_orders_rejected_count_previous + total_orders_accepted_count_previous
        ) AS unprocessed_orders_count_previous,
        COUNT(*) FILTER ( WHERE total_orders_count_current = 0 )
            AS no_orders_count_current,
        COUNT(*) FILTER ( WHERE total_orders_count_previous = 0
            AND client_created_at < $4
        ) AS no_orders_count_previous,
        COUNT(*) FILTER (
            WHERE last_call_event_type_current = 'FINISHED'
                AND last_call_talk_duration_current BETWEEN 1 AND 9
        ) AS short_last_call_count_current,
        COUNT(*) FILTER (
            WHERE last_call_event_type_previous = 'FINISHED'
                AND last_call_talk_duration_previous BETWEEN 1 AND 9
        ) AS short_last_call_count_previous,
        COUNT(*) FILTER (
            WHERE last_call_event_type_current = 'FINISHED'
                AND last_call_talk_duration_current = 0
        ) AS missed_last_call_count_current,
        COUNT(*) FILTER (
            WHERE last_call_event_type_previous = 'FINISHED'
                AND last_call_talk_duration_previous = 0
        ) AS missed_last_call_count_previous
    FROM events_stat
)
SELECT
    segments_sizes.*,
    total.*
FROM segments_sizes
RIGHT JOIN (
    SELECT
        count(*) AS total_clients_count_current,
        count(*) FILTER ( WHERE created_at < $4 ) AS total_clients_count_previous
    FROM clients
    WHERE biz_id = $1
) AS total ON TRUE
"""  # noqa


list_labels = """
    WITH unnested_labels AS (
        SELECT unnest(labels) AS label
        FROM clients
        WHERE biz_id = $1
    )
    SELECT label, count(*) AS count
    FROM unnested_labels
    GROUP BY label
"""


regular_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
),
clients_stats_by_slot AS (
    SELECT slot,
           clients.id AS client_id,
           count(*) AS total_count
    FROM slots
    LEFT JOIN clients ON clients.biz_id = $1
         AND clients.created_at < slot
    LEFT JOIN order_events ON clients.id = order_events.client_id
        AND order_events.biz_id = $1
        AND event_type = 'CREATED'
        AND event_timestamp BETWEEN slot - INTERVAL '90 day' AND slot
    GROUP BY slot, clients.id
)
SELECT
    slot,
    count(client_id) FILTER ( WHERE total_count >= 3 ) as c
FROM clients_stats_by_slot
GROUP BY slot
ORDER BY slot
"""

active_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
)
SELECT slot, count(distinct client_id) AS c
FROM (
    SELECT client_id, event_timestamp
    FROM order_events
    WHERE biz_id = $1 AND event_type = 'ACCEPTED'
    UNION ALL
    SELECT client_id, event_timestamp
    FROM call_events
    WHERE biz_id = $1
) client_ids
RIGHT JOIN slots ON event_timestamp BETWEEN slot - INTERVAL '90 day' AND slot
GROUP BY slot
ORDER BY slot
"""

lost_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
),
clients_stats_by_slot AS (
    SELECT slot,
        clients.id AS client_id,

        count(*) FILTER (
            WHERE order_events.event_type = 'CREATED'
        ) AS total_orders_count,
        count(*) FILTER (
            WHERE order_events.event_type = 'CREATED'
            AND order_events.event_timestamp BETWEEN slot - INTERVAL '90 day' AND slot
        ) AS created_orders_count,
        count(*) FILTER (
            WHERE order_events.event_type = 'REJECTED'
            AND order_events.event_timestamp BETWEEN slot - INTERVAL '90 day' AND slot
        ) AS rejected_orders_count,

        count(*) FILTER (
            WHERE call_events.event_type IS NOT NULL
        ) AS total_calls_count,
        count(*) FILTER (
            WHERE call_events.event_timestamp BETWEEN slot - INTERVAL '90 day' AND slot
        ) AS recent_calls_count
    FROM slots
    LEFT JOIN clients ON clients.biz_id = $1
         AND clients.created_at < slot
    LEFT JOIN order_events ON clients.id = order_events.client_id
        AND order_events.biz_id = $1
    LEFT JOIN call_events ON clients.id = call_events.client_id
        AND call_events.biz_id = $1
    GROUP BY slot, clients.id
)
SELECT
    slot,
    count(client_id) FILTER (
        WHERE total_orders_count + total_calls_count > 0
        AND recent_calls_count = 0
        AND created_orders_count <= rejected_orders_count
    ) as c
FROM clients_stats_by_slot
GROUP BY slot
ORDER BY slot
"""

no_orders_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
)
SELECT slot, count(distinct clients.id) AS c
FROM slots
LEFT JOIN clients ON clients.biz_id = $1
    AND clients.created_at < slot
LEFT JOIN order_events ON clients.id = order_events.client_id
    AND event_timestamp < slot
WHERE event_type IS NULL
GROUP BY slot
ORDER BY slot
"""


unprocessed_orders_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
),
clients_stats_by_slot AS (
    SELECT slot,
        clients.id AS client_id,
        count(*) FILTER ( WHERE event_type = 'CREATED' ) AS total_count,
        count(*) FILTER ( WHERE event_type != 'CREATED' ) AS resolved_count
    FROM slots
    LEFT JOIN clients ON clients.biz_id = $1
        AND clients.created_at < slot
    LEFT JOIN order_events ON clients.id = order_events.client_id
        AND order_events.biz_id = $1
        AND order_events.event_timestamp < slot
    GROUP BY slot, clients.id
)
SELECT
    slot,
    count(client_id) FILTER ( WHERE total_count > resolved_count ) as c
FROM clients_stats_by_slot
GROUP BY slot
ORDER BY slot
"""


all_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
)
SELECT slot,
       count(clients.id) AS c
FROM slots
LEFT JOIN clients ON clients.biz_id = $1
     AND clients.created_at < slot
GROUP BY slot
ORDER BY slot
"""

short_last_call_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
),
clients_stats_by_slot AS (
    SELECT DISTINCT ON (slot, client_id) slot, client_id, event_type, talk_duration
    FROM slots
    LEFT JOIN call_events ON biz_id = $1
        AND call_events.event_timestamp < slot
    ORDER BY slot, client_id, event_timestamp DESC
)
SELECT
    slot,
    count(client_id) FILTER (
        WHERE event_type = 'FINISHED' AND talk_duration BETWEEN 1 AND 9
    ) as c
FROM clients_stats_by_slot
GROUP BY slot
ORDER BY slot
"""

missed_last_call_segment_statistics = """
WITH
slots AS (
    SELECT date_trunc('month', slot::timestamptz) + INTERVAL '1 month - 1 day' as slot
    FROM generate_series(
        $2::timestamptz - INTERVAL '1 year',
        $2::timestamptz,
        INTERVAL '1 month'
    ) slot
),
clients_stats_by_slot AS (
    SELECT DISTINCT ON (slot, client_id) slot, client_id, event_type, talk_duration
    FROM slots
    LEFT JOIN call_events ON biz_id = $1
        AND call_events.event_timestamp < slot
    ORDER BY slot, client_id, event_timestamp DESC
)
SELECT
    slot,
    count(client_id) FILTER (
        WHERE event_type = 'FINISHED' AND talk_duration = 0
    ) as c
FROM clients_stats_by_slot
GROUP BY slot
ORDER BY slot
"""
