<?php
/**
 * election-ballot-core.php — هسته صندوق‌محور: فازها، POI، تخصیص چندصندوق
 */
if ( ! defined( 'ABSPATH' ) ) exit;

trait Election_Ballot_Core {

    public const PHASES = [
        'pre_campaign' => 'قبل از تبلیغات — شناسایی اطراف صندوق',
        'campaign'       => '۱۰ روز تبلیغات — ارسال کالا',
        'election_day'   => 'روز رأی‌گیری — حضور و تشویق',
    ];

    public const POI_TYPES = [
        'bakery'    => 'نانوایی',
        'school'    => 'مدرسه',
        'mosque'    => 'مسجد',
        'hospital'  => 'درمانگاه/بیمارستان',
        'shop'      => 'فروشگاه',
        'park'      => 'بوستان',
        'office'    => 'اداره/سازمان',
        'other'     => 'سایر',
    ];

    public static function user_stations_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_user_stations';
    }

    public static function station_pois_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_station_pois';
    }

    public static function phase_config_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_phase_config';
    }

    public static function station_tasks_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_station_tasks';
    }

    public static function briefings_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_briefings';
    }

    public static function shipments_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_shipments';
    }

    public static function org_units_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_org_units';
    }

    public static function org_assignments_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_org_assignments';
    }

    public static function districts_table(): string {
        global $wpdb;
        return $wpdb->prefix . 'election_districts';
    }

    public static function current_phase(): string {
        global $wpdb;
        $t = self::phase_config_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return 'pre_campaign';
        }
        $p = $wpdb->get_var( "SELECT current_phase FROM {$t} ORDER BY id DESC LIMIT 1" );
        return $p && isset( self::PHASES[ $p ] ) ? $p : 'pre_campaign';
    }

    public static function phase_info(): array {
        global $wpdb;
        $t = self::phase_config_table();
        $row = $wpdb->get_row( "SELECT * FROM {$t} ORDER BY id DESC LIMIT 1", ARRAY_A ) ?: [];
        $phase = self::current_phase();
        return array_merge( $row, [
            'current_phase' => $phase,
            'phase_label'   => self::PHASES[ $phase ] ?? $phase,
            'phases'        => self::PHASES,
        ] );
    }

    public static function fmt_station( array $row ): array {
        $row['poi_count'] = (int) ( $row['poi_count'] ?? 0 );
        return $row;
    }

    public static function list_stations_enriched( array $opts = [] ): array {
        global $wpdb;
        $st = self::stations_table();
        $poi_t = self::station_pois_table();
        $has_poi = $wpdb->get_var( "SHOW TABLES LIKE '{$poi_t}'" ) === $poi_t;

        $w = [ '1=1' ];
        $args = [];
        if ( ! empty( $opts['district_id'] ) ) {
            $w[] = 's.district_id = %d';
            $args[] = (int) $opts['district_id'];
        }
        if ( ! empty( $opts['neighborhood'] ) ) {
            $w[] = 's.neighborhood = %s';
            $args[] = sanitize_text_field( $opts['neighborhood'] );
        }

        $poi_sub = $has_poi
            ? ", (SELECT COUNT(*) FROM {$poi_t} p WHERE p.station_id = s.id) AS poi_count"
            : ', 0 AS poi_count';

        $sql = "SELECT s.*{$poi_sub} FROM {$st} s WHERE " . implode( ' AND ', $w ) . ' ORDER BY s.district_id, s.neighborhood, s.code';
        $rows = $args ? $wpdb->get_results( $wpdb->prepare( $sql, ...$args ), ARRAY_A ) : $wpdb->get_results( $sql, ARRAY_A );
        return array_map( [ __CLASS__, 'fmt_station' ], $rows ?: [] );
    }

    public static function user_station_ids( int $uid ): array {
        global $wpdb;
        $t = self::user_stations_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        return array_map( 'intval', $wpdb->get_col( $wpdb->prepare(
            "SELECT station_id FROM {$t} WHERE user_id = %d ORDER BY is_primary DESC, id", $uid
        ) ) ?: [] );
    }

    public static function user_stations( int $uid ): array {
        $ids = self::user_station_ids( $uid );
        if ( ! $ids ) {
            return [];
        }
        global $wpdb;
        $st = self::stations_table();
        $ph = implode( ',', array_fill( 0, count( $ids ), '%d' ) );
        $rows = $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM {$st} WHERE id IN ($ph)", ...$ids
        ), ARRAY_A ) ?: [];
        $by_id = [];
        foreach ( $rows as $r ) {
            $by_id[ (int) $r['id'] ] = self::fmt_station( $r );
        }
        return array_values( array_filter( array_map( fn( $id ) => $by_id[ $id ] ?? null, $ids ) ) );
    }

    public static function assign_stations_to_user( int $uid, array $station_ids, string $role = 'supporter' ): array {
        global $wpdb;
        $t = self::user_stations_table();
        $wpdb->query( $wpdb->prepare( "DELETE FROM {$t} WHERE user_id = %d", $uid ) );
        $station_ids = array_values( array_unique( array_map( 'intval', $station_ids ) ) );
        foreach ( $station_ids as $i => $sid ) {
            $wpdb->insert( $t, [
                'user_id'    => $uid,
                'station_id' => $sid,
                'role'       => $role,
                'is_primary' => $i === 0 ? 1 : 0,
                'assigned_at'=> current_time( 'mysql' ),
            ] );
        }
        self::seed_tasks_for_user_stations( $uid, $station_ids );
        return [ 'success' => true, 'count' => count( $station_ids ) ];
    }

    public static function list_pois( ?int $station_id = null, ?int $uid = null ): array {
        global $wpdb;
        $t = self::station_pois_table();
        $w = [ '1=1' ];
        $args = [];
        if ( $station_id ) {
            $w[] = 'station_id = %d';
            $args[] = $station_id;
        }
        if ( $uid ) {
            $w[] = 'user_id = %d';
            $args[] = $uid;
        }
        $sql = "SELECT * FROM {$t} WHERE " . implode( ' AND ', $w ) . ' ORDER BY station_id, poi_type, id DESC LIMIT 500';
        $rows = $args ? $wpdb->get_results( $wpdb->prepare( $sql, ...$args ), ARRAY_A ) : $wpdb->get_results( $sql, ARRAY_A );
        return array_map( function( $r ) {
            $r['poi_type_label'] = self::POI_TYPES[ $r['poi_type'] ?? '' ] ?? ( $r['poi_type'] ?? '' );
            return $r;
        }, $rows ?: [] );
    }

    public static function add_poi( int $uid, array $data ): array {
        global $wpdb;
        $sid = (int) ( $data['station_id'] ?? 0 );
        if ( ! $sid ) {
            return [ 'success' => false, 'message' => 'صندوق الزامی است' ];
        }
        if ( ! self::can_manage( $uid ) ) {
            $allowed = self::user_station_ids( $uid );
            if ( ! in_array( $sid, $allowed, true ) ) {
                return [ 'success' => false, 'message' => 'این صندوق به شما تخصیص نشده' ];
            }
        }
        $type = sanitize_key( $data['poi_type'] ?? 'other' );
        if ( ! isset( self::POI_TYPES[ $type ] ) ) {
            $type = 'other';
        }
        $wpdb->insert( self::station_pois_table(), [
            'station_id' => $sid,
            'user_id'    => $uid,
            'poi_type'   => $type,
            'name'       => sanitize_text_field( $data['name'] ?? '' ),
            'address'    => sanitize_textarea_field( $data['address'] ?? '' ),
            'notes'      => sanitize_textarea_field( $data['notes'] ?? '' ),
            'phase'      => self::current_phase(),
            'verified'   => 0,
            'created_at' => current_time( 'mysql' ),
        ] );
        return [ 'success' => true, 'id' => (int) $wpdb->insert_id ];
    }

    public static function list_tasks( int $uid, ?string $phase = null ): array {
        global $wpdb;
        $t = self::station_tasks_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        $phase = $phase ?: self::current_phase();
        if ( self::can_manage( $uid ) ) {
            return $wpdb->get_results( $wpdb->prepare(
                "SELECT * FROM {$t} WHERE phase = %s ORDER BY FIELD(status,'pending','in_progress','done'), id",
                $phase
            ), ARRAY_A ) ?: [];
        }
        return $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM {$t} WHERE user_id = %d AND phase = %s ORDER BY FIELD(status,'pending','in_progress','done'), id",
            $uid, $phase
        ), ARRAY_A ) ?: [];
    }

    public static function complete_task( int $uid, int $task_id ): array {
        global $wpdb;
        $t = self::station_tasks_table();
        $task = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$t} WHERE id = %d", $task_id ), ARRAY_A );
        if ( ! $task ) {
            return [ 'success' => false, 'message' => 'وظیفه یافت نشد' ];
        }
        if ( ! self::can_manage( $uid ) && (int) $task['user_id'] !== $uid ) {
            return [ 'success' => false, 'message' => 'دسترسی ندارید' ];
        }
        $wpdb->update( $t, [
            'status'       => 'done',
            'completed_at' => current_time( 'mysql' ),
        ], [ 'id' => $task_id ] );
        return [ 'success' => true ];
    }

    public static function seed_tasks_for_user_stations( int $uid, array $station_ids ): void {
        global $wpdb;
        $t = self::station_tasks_table();
        $st = self::stations_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return;
        }

        $task_defs = [
            'pre_campaign' => [
                [ 'poi_survey', 'شناسایی نانوایی نزدیک صندوق', 'نام و آدرس نانوایی‌های اطراف را ثبت کنید.' ],
                [ 'poi_survey', 'شناسایی مدرسه و مسجد', 'مدارس، مساجد و مراکز تجمع را شناسایی کنید.' ],
                [ 'intel_report', 'گزارش اولیه محله', 'خلاصه وضعیت اجتماعی اطراف صندوق را گزارش دهید.' ],
            ],
            'campaign' => [
                [ 'material', 'دریافت کالای تبلیغاتی', 'بسته بارکددار تخصیص‌یافته به صندوق را دریافت و تأیید کنید.' ],
                [ 'distribution', 'توزیع در محدوده صندوق', 'طبق برنامه، مواد تبلیغاتی را در اطراف صندوق توزیع کنید.' ],
                [ 'briefing_read', 'مطالعه شعار و اقدامات کاندید', 'پیام‌های دریافتی برای منطقه را مطالعه کنید.' ],
            ],
            'election_day' => [
                [ 'presence', 'حضور در اطراف صندوق', 'از صبح در محل صندوق حضور داشته باشید.' ],
                [ 'persuasion', 'تشویق رأی‌دهندگان مردد', 'با احترام، رأی‌دهندگان مردد را به کاندید مورد نظر تشویق کنید.' ],
                [ 'day_report', 'گزارش پایان روز', 'خلاصه حضور و بازخورد روز انتخابات را ثبت کنید.' ],
            ],
        ];

        foreach ( $station_ids as $sid ) {
            $station = $wpdb->get_row( $wpdb->prepare( "SELECT name FROM {$st} WHERE id = %d", $sid ), ARRAY_A );
            $sname = $station['name'] ?? "صندوق #{$sid}";
            foreach ( $task_defs as $phase => $tasks ) {
                foreach ( $tasks as [ $type, $title, $body ] ) {
                    $exists = (int) $wpdb->get_var( $wpdb->prepare(
                        "SELECT id FROM {$t} WHERE user_id=%d AND station_id=%d AND phase=%s AND task_type=%s AND title=%s",
                        $uid, $sid, $phase, $type, $title
                    ) );
                    if ( $exists ) continue;
                    $wpdb->insert( $t, [
                        'user_id'    => $uid,
                        'station_id' => $sid,
                        'phase'      => $phase,
                        'task_type'  => $type,
                        'title'      => $title,
                        'body'       => "«{$sname}» — {$body}",
                        'status'     => 'pending',
                        'created_at' => current_time( 'mysql' ),
                    ] );
                }
            }
        }
    }

    public static function list_briefings( int $uid ): array {
        global $wpdb;
        $t = self::briefings_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        $phase = self::current_phase();
        $station_ids = self::user_station_ids( $uid );

        if ( self::can_manage( $uid ) ) {
            return $wpdb->get_results( $wpdb->prepare(
                "SELECT * FROM {$t} WHERE phase = %s OR phase IS NULL ORDER BY id DESC LIMIT 100", $phase
            ), ARRAY_A ) ?: [];
        }

        $rows = $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM {$t} WHERE (phase = %s OR phase IS NULL) AND (audience = 'all' OR audience = 'supporter') ORDER BY id DESC LIMIT 50",
            $phase
        ), ARRAY_A ) ?: [];

        if ( $station_ids ) {
            $ph = implode( ',', array_fill( 0, count( $station_ids ), '%d' ) );
            $station_rows = $wpdb->get_results( $wpdb->prepare(
                "SELECT * FROM {$t} WHERE station_id IN ($ph) ORDER BY id DESC LIMIT 30", ...$station_ids
            ), ARRAY_A ) ?: [];
            $ids = array_column( $rows, 'id' );
            foreach ( $station_rows as $sr ) {
                if ( ! in_array( $sr['id'], $ids, true ) ) {
                    $rows[] = $sr;
                }
            }
        }
        return $rows;
    }

    public static function add_briefing( array $data ): array {
        global $wpdb;
        $wpdb->insert( self::briefings_table(), [
            'title'         => sanitize_text_field( $data['title'] ?? '' ),
            'body'          => sanitize_textarea_field( $data['body'] ?? '' ),
            'briefing_type' => sanitize_key( $data['briefing_type'] ?? 'instruction' ),
            'district_id'   => (int) ( $data['district_id'] ?? 0 ) ?: null,
            'station_id'    => (int) ( $data['station_id'] ?? 0 ) ?: null,
            'phase'         => sanitize_key( $data['phase'] ?? self::current_phase() ),
            'audience'      => sanitize_key( $data['audience'] ?? 'supporter' ),
            'created_at'    => current_time( 'mysql' ),
        ] );
        return [ 'success' => true, 'id' => (int) $wpdb->insert_id ];
    }

    public static function list_shipments( int $uid ): array {
        global $wpdb;
        $t = self::shipments_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        if ( self::can_manage( $uid ) ) {
            return $wpdb->get_results( "SELECT * FROM {$t} ORDER BY id DESC LIMIT 100", ARRAY_A ) ?: [];
        }
        $sids = self::user_station_ids( $uid );
        if ( ! $sids ) return [];
        $ph = implode( ',', array_fill( 0, count( $sids ), '%d' ) );
        return $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM {$t} WHERE station_id IN ($ph) OR user_id = %d ORDER BY id DESC", ...array_merge( $sids, [ $uid ] )
        ), ARRAY_A ) ?: [];
    }

    public static function confirm_shipment( int $uid, int $shipment_id ): array {
        global $wpdb;
        $t = self::shipments_table();
        $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$t} WHERE id = %d", $shipment_id ), ARRAY_A );
        if ( ! $row ) {
            return [ 'success' => false, 'message' => 'محموله یافت نشد' ];
        }
        if ( ! self::can_manage( $uid ) && (int) $row['user_id'] !== $uid ) {
            $allowed = self::user_station_ids( $uid );
            if ( ! in_array( (int) $row['station_id'], $allowed, true ) ) {
                return [ 'success' => false, 'message' => 'دسترسی ندارید' ];
            }
        }
        $wpdb->update( $t, [
            'status'      => 'received',
            'received_at' => current_time( 'mysql' ),
        ], [ 'id' => $shipment_id ] );
        return [ 'success' => true ];
    }

    public static function list_districts(): array {
        global $wpdb;
        $t = self::districts_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$t}'" ) !== $t ) {
            return [];
        }
        $st = self::stations_table();
        return $wpdb->get_results(
            "SELECT d.*, (SELECT COUNT(*) FROM {$st} s WHERE s.district_id = d.id) AS station_count
             FROM {$t} d ORDER BY d.sort_order, d.id",
            ARRAY_A
        ) ?: [];
    }

    public static function org_tree(): array {
        global $wpdb;
        $ut = self::org_units_table();
        $at = self::org_assignments_table();
        if ( $wpdb->get_var( "SHOW TABLES LIKE '{$ut}'" ) !== $ut ) {
            return [];
        }
        $units = $wpdb->get_results( "SELECT * FROM {$ut} ORDER BY parent_id, sort_order, id", ARRAY_A ) ?: [];
        $assigns = $wpdb->get_results(
            "SELECT a.*, u.display_name FROM {$at} a
             LEFT JOIN {$wpdb->users} u ON u.ID = a.user_id
             ORDER BY a.unit_id, a.sort_order", ARRAY_A
        ) ?: [];
        $by_unit = [];
        foreach ( $assigns as $a ) {
            $by_unit[ (int) $a['unit_id'] ][] = $a;
        }
        foreach ( $units as &$u ) {
            $u['members'] = $by_unit[ (int) $u['id'] ] ?? [];
        }
        return $units;
    }

    public static function ballot_dashboard( int $uid ): array {
        if ( self::can_manage( $uid ) ) {
            return [
                'role'       => 'admin',
                'tagline'    => 'مدیریت صندوق‌ها — GIS/ERP — تشکیلات ستاد',
                'phase'      => self::phase_info(),
                'stats'      => self::stats(),
                'erp'        => self::admin_erp_intel(),
                'gis'        => self::admin_gis_intel(),
                'districts'  => self::list_districts(),
                'stations'   => self::list_stations_enriched(),
                'org'        => self::org_tree(),
            ];
        }

        $stations = self::user_stations( $uid );
        $phase    = self::phase_info();
        $tasks    = self::list_tasks( $uid );
        $pending  = count( array_filter( $tasks, fn( $t ) => ( $t['status'] ?? '' ) === 'pending' ) );

        $role = 'supporter';
        $branch = self::get_branch_by_user( $uid );
        if ( $branch ) {
            $role = 'district_lead';
        }

        return [
            'role'            => $role,
            'tagline'         => 'مدیریت بر اساس صندوق(های) تخصیص‌یافته — ' . ( $phase['phase_label'] ?? '' ),
            'phase'           => $phase,
            'stations'        => $stations,
            'station_count'   => count( $stations ),
            'tasks'           => $tasks,
            'tasks_pending'   => $pending,
            'pois'            => self::list_pois( null, $uid ),
            'briefings'       => self::list_briefings( $uid ),
            'shipments'       => self::list_shipments( $uid ),
            'packages'        => self::list_packages( null ),
            'content'         => self::content_for_user( $uid ),
            'poi_types'       => self::POI_TYPES,
        ];
    }
}
