<?php

/**
 * Contact Model
 * Handles contact management with birthday tracking
 */
class Contact {
    
    private $db;
    
    public $id;
    public $user_id;
    public $full_name;
    public $contact_number;
    public $email;
    public $designation;
    public $village;
    public $date_of_birth;
    public $note;
    public $status;
    public $created_at;
    public $updated_at;
    
    public function __construct() {
        $this->db = Database::getInstance();
    }
    
    /**
     * Create a new contact
     * 
     * @param array $data
     * @return int|false Contact ID on success, false on failure
     */
    public function create($data) {
        // Validate required fields
        if (empty($data['user_id']) || empty($data['full_name']) || empty($data['contact_number']) || empty($data['date_of_birth'])) {
            return false;
        }
        
        // Validate phone number (exactly 10 digits)
        if (!$this->validatePhoneNumber($data['contact_number'])) {
            return false;
        }
        
        // Check for duplicate
        if ($this->checkDuplicate($data['user_id'], $data['contact_number'])) {
            return false;
        }
        
        $sql = "INSERT INTO contacts (user_id, full_name, contact_number, email, designation, village, date_of_birth, note, status) 
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
        
        $status = isset($data['status']) ? $data['status'] : 'active';
        
        $this->db->execute($sql, [
            $data['user_id'],
            $data['full_name'],
            $data['contact_number'],
            $data['email'] ?? '',
            $data['designation'] ?? '',
            $data['village'] ?? '',
            $data['date_of_birth'],
            $data['note'] ?? '',
            $status
        ]);
        
        return $this->db->lastInsertId();
    }
    
    /**
     * Find contact by ID
     * 
     * @param int $id
     * @return Contact|false
     */
    public function findById($id) {
        $sql = "SELECT * FROM contacts WHERE id = ? LIMIT 1";
        $contact = $this->db->fetchOne($sql, [$id]);
        
        if ($contact) {
            $this->fillFromArray($contact);
            return $this;
        }
        
        return false;
    }
    
    /**
     * Update contact
     * 
     * @param int $id
     * @param array $data
     * @return bool
     */
    public function update($id, $data) {
        $fields = [];
        $values = [];
        
        // Build update query dynamically
        if (isset($data['user_id'])) {
            $fields[] = "user_id = ?";
            $values[] = $data['user_id'];
        }
        
        if (isset($data['full_name'])) {
            $fields[] = "full_name = ?";
            $values[] = $data['full_name'];
        }
        
        if (isset($data['contact_number'])) {
            // Validate phone number
            if (!$this->validatePhoneNumber($data['contact_number'])) {
                return false;
            }
            
            // Check for duplicate (excluding current contact)
            $existing = $this->checkDuplicate($data['user_id'] ?? $this->user_id, $data['contact_number'], $id);
            if ($existing) {
                return false;
            }
            
            $fields[] = "contact_number = ?";
            $values[] = $data['contact_number'];
        }
        
        if (isset($data['email'])) {
            $fields[] = "email = ?";
            $values[] = $data['email'];
        }
        
        if (isset($data['designation'])) {
            $fields[] = "designation = ?";
            $values[] = $data['designation'];
        }
        
        if (isset($data['village'])) {
            $fields[] = "village = ?";
            $values[] = $data['village'];
        }
        
        if (isset($data['date_of_birth'])) {
            $fields[] = "date_of_birth = ?";
            $values[] = $data['date_of_birth'];
        }
        
        if (isset($data['note'])) {
            $fields[] = "note = ?";
            $values[] = $data['note'];
        }
        
        if (isset($data['status'])) {
            $fields[] = "status = ?";
            $values[] = $data['status'];
        }
        
        if (empty($fields)) {
            return false;
        }
        
        $values[] = $id;
        $sql = "UPDATE contacts SET " . implode(', ', $fields) . " WHERE id = ?";
        
        try {
            $this->db->execute($sql, $values);
            return true;
        } catch (Exception $e) {
            logError("Contact update failed: " . $e->getMessage(), ['contact_id' => $id]);
            return false;
        }
    }
    
    /**
     * Delete contact
     * 
     * @param int $id
     * @return bool
     */
    public function delete($id) {
        $sql = "DELETE FROM contacts WHERE id = ?";
        return $this->db->execute($sql, [$id]) > 0;
    }
    
    /**
     * Get all contacts
     * 
     * @param int|null $userId Filter by user ID (null for all)
     * @return array
     */
    public function getAll($userId = null) {
        $sql = "SELECT c.*, u.username 
                FROM contacts c 
                LEFT JOIN users u ON c.user_id = u.id";
        
        $params = [];
        if ($userId !== null) {
            $sql .= " WHERE c.user_id = ?";
            $params[] = $userId;
        }
        
        $sql .= " ORDER BY c.created_at DESC";
        
        return $this->db->fetchAll($sql, $params);
    }
    
    /**
     * Get contacts by user ID
     * 
     * @param int $userId
     * @return array
     */
    public function getByUser($userId) {
        $sql = "SELECT * FROM contacts WHERE user_id = ? ORDER BY full_name ASC";
        return $this->db->fetchAll($sql, [$userId]);
    }
    
    /**
     * Get today's birthdays for a user
     * 
     * @param int $userId
     * @return array
     */
    public function getTodayBirthdays($userId) {
        $sql = "SELECT * FROM contacts 
                WHERE user_id = ? 
                AND status = 'active'
                AND MONTH(date_of_birth) = MONTH(CURDATE()) 
                AND DAY(date_of_birth) = DAY(CURDATE())
                ORDER BY full_name ASC";
        return $this->db->fetchAll($sql, [$userId]);
    }
    
    /**
     * Get all today's birthdays (all users)
     * 
     * @return array
     */
    public function getAllTodayBirthdays() {
        $sql = "SELECT c.*, u.username 
                FROM contacts c 
                LEFT JOIN users u ON c.user_id = u.id 
                WHERE c.status = 'active'
                AND MONTH(c.date_of_birth) = MONTH(CURDATE()) 
                AND DAY(c.date_of_birth) = DAY(CURDATE())
                ORDER BY c.full_name ASC";
        return $this->db->fetchAll($sql);
    }
    
    /**
     * Get upcoming birthdays (next N days)
     * 
     * @param int $days
     * @param int|null $userId
     * @return array
     */
    public function getUpcomingBirthdays($days = 7, $userId = null) {
        $sql = "SELECT c.*, u.username,
                CONCAT(
                    YEAR(CURDATE()), '-',
                    LPAD(MONTH(c.date_of_birth), 2, '0'), '-',
                    LPAD(DAY(c.date_of_birth), 2, '0')
                ) as next_birthday
                FROM contacts c
                LEFT JOIN users u ON c.user_id = u.id
                WHERE c.status = 'active'";
        
        $params = [];
        if ($userId) {
            $sql .= " AND c.user_id = ?";
            $params[] = $userId;
        }
        
        $sql .= " HAVING next_birthday BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL ? DAY)
                  ORDER BY next_birthday ASC";
        
        $params[] = $days;
        
        return $this->db->fetchAll($sql, $params);
    }
    
     /**
     * Get next 3 days birthdays for a user (tomorrow, day 2, day 3)
     *
     * @param int $userId
     * @return array Birthdays grouped by day with date information
     */
    public function getNextThreeDaysBirthdays($userId) {
        $sql = "SELECT *,
                CASE
                    WHEN MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 DAY))
                         AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 1 DAY)) THEN 1
                    WHEN MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 2 DAY))
                         AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 2 DAY)) THEN 2
                    WHEN MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 3 DAY))
                         AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 3 DAY)) THEN 3
                END as days_until,
                DATE_ADD(CURDATE(), INTERVAL
                    CASE
                        WHEN MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 DAY))
                             AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 1 DAY)) THEN 1
                        WHEN MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 2 DAY))
                             AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 2 DAY)) THEN 2
                        WHEN MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 3 DAY))
                             AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 3 DAY)) THEN 3
                    END DAY) as birthday_date
                FROM contacts
                WHERE user_id = ?
                AND status = 'active'
                AND (
                    (MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 1 DAY))
                     AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 1 DAY)))
                    OR
                    (MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 2 DAY))
                     AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 2 DAY)))
                    OR
                    (MONTH(date_of_birth) = MONTH(DATE_ADD(CURDATE(), INTERVAL 3 DAY))
                     AND DAY(date_of_birth) = DAY(DATE_ADD(CURDATE(), INTERVAL 3 DAY)))
                )
                ORDER BY days_until ASC, full_name ASC";

        $allBirthdays = $this->db->fetchAll($sql, [$userId]);

        // Group by days_until
        $result = [
            'day1' => [],
            'day2' => [],
            'day3' => []
        ];

        foreach ($allBirthdays as $birthday) {
            $dayKey = 'day' . $birthday['days_until'];
            $result[$dayKey][] = $birthday;
        }

        return $result;
    }
    
    /**
     * Search contacts
     * 
     * @param string $query
     * @param int|null $userId
     * @return array
     */
    public function search($query, $userId = null) {
        $sql = "SELECT c.*, u.username 
                FROM contacts c 
                LEFT JOIN users u ON c.user_id = u.id 
                WHERE (c.full_name LIKE ? OR c.contact_number LIKE ? OR c.designation LIKE ? OR c.village LIKE ? OR c.note LIKE ?)";
        
        $searchTerm = '%' . $query . '%';
        $params = [$searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm];
        
        if ($userId) {
            $sql .= " AND c.user_id = ?";
            $params[] = $userId;
        }
        
        $sql .= " ORDER BY c.full_name ASC";
        
        return $this->db->fetchAll($sql, $params);
    }
    
    /**
     * Check for duplicate contact number for a user
     * 
     * @param int $userId
     * @param string $contactNumber
     * @param int|null $excludeId
     * @return Contact|false
     */
    public function checkDuplicate($userId, $contactNumber, $excludeId = null) {
        $sql = "SELECT * FROM contacts WHERE user_id = ? AND contact_number = ?";
        $params = [$userId, $contactNumber];
        
        if ($excludeId) {
            $sql .= " AND id != ?";
            $params[] = $excludeId;
        }
        
        $sql .= " LIMIT 1";
        
        $contact = $this->db->fetchOne($sql, $params);
        
        if ($contact) {
            $this->fillFromArray($contact);
            return $this;
        }
        
        return false;
    }
    
    /**
     * Validate phone number (exactly 10 digits)
     * 
     * @param string $phone
     * @return bool
     */
    public function validatePhoneNumber($phone) {
        return strlen($phone) === 10 && ctype_digit($phone);
    }
    
    /**
     * Count total contacts
     * 
     * @param int|null $userId
     * @return int
     */
    public function count($userId = null) {
        if ($userId) {
            $sql = "SELECT COUNT(*) as count FROM contacts WHERE user_id = ?";
            $result = $this->db->fetchOne($sql, [$userId]);
        } else {
            $sql = "SELECT COUNT(*) as count FROM contacts";
            $result = $this->db->fetchOne($sql);
        }
        return $result['count'] ?? 0;
    }
    
    /**
     * Count active contacts
     * 
     * @param int|null $userId
     * @return int
     */
    public function countActive($userId = null) {
        if ($userId) {
            $sql = "SELECT COUNT(*) as count FROM contacts WHERE user_id = ? AND status = 'active'";
            $result = $this->db->fetchOne($sql, [$userId]);
        } else {
            $sql = "SELECT COUNT(*) as count FROM contacts WHERE status = 'active'";
            $result = $this->db->fetchOne($sql);
        }
        return $result['count'] ?? 0;
    }
    
    /**
     * Fill object properties from array
     * 
     * @param array $data
     */
    private function fillFromArray($data) {
        $this->id = $data['id'] ?? null;
        $this->user_id = $data['user_id'] ?? null;
        $this->full_name = $data['full_name'] ?? null;
        $this->contact_number = $data['contact_number'] ?? null;
        $this->email = $data['email'] ?? null;
        $this->designation = $data['designation'] ?? null;
        $this->village = $data['village'] ?? null;
        $this->date_of_birth = $data['date_of_birth'] ?? null;
        $this->note = $data['note'] ?? null;
        $this->status = $data['status'] ?? null;
        $this->created_at = $data['created_at'] ?? null;
        $this->updated_at = $data['updated_at'] ?? null;
    }
    
    /**
     * Convert contact to array
     * 
     * @return array
     */
    public function toArray() {
        return [
            'id' => $this->id,
            'user_id' => $this->user_id,
            'full_name' => $this->full_name,
            'contact_number' => $this->contact_number,
            'email' => $this->email,
            'designation' => $this->designation,
            'village' => $this->village,
            'date_of_birth' => $this->date_of_birth,
            'note' => $this->note,
            'status' => $this->status,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at
        ];
    }
    
    /**
     * Get paginated contacts
     * 
     * @param int $limit
     * @param int $offset
     * @param int|null $userId Filter by user ID (null for all)
     * @return array
     */
    public function getPaginated($limit = 10, $offset = 0, $userId = null) {
        $sql = "SELECT c.*, u.username 
                FROM contacts c
                LEFT JOIN users u ON c.user_id = u.id";
        
        $params = [];
        if ($userId !== null) {
            $sql .= " WHERE c.user_id = ?";
            $params[] = $userId;
        }
        
        $sql .= " ORDER BY c.created_at DESC LIMIT ? OFFSET ?";
        $params[] = $limit;
        $params[] = $offset;
        
        return $this->db->fetchAll($sql, $params);
    }
    
    /**
     * Search contacts with pagination
     * 
     * @param string $query
     * @param int $limit
     * @param int $offset
     * @param int|null $userId Filter by user ID (null for all)
     * @return array
     */
    public function searchPaginated($query, $limit = 10, $offset = 0, $userId = null) {
        $searchTerm = '%' . $query . '%';
        $sql = "SELECT c.*, u.username 
                FROM contacts c
                LEFT JOIN users u ON c.user_id = u.id
                WHERE c.full_name LIKE ? OR c.contact_number LIKE ? OR c.email LIKE ? OR c.designation LIKE ? OR c.village LIKE ?";
        
        $params = [$searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm];
        
        if ($userId !== null) {
            $sql .= " AND c.user_id = ?";
            $params[] = $userId;
        }
        
        $sql .= " ORDER BY c.created_at DESC LIMIT ? OFFSET ?";
        $params[] = $limit;
        $params[] = $offset;
        
        return $this->db->fetchAll($sql, $params);
    }
    
    /**
     * Count total contacts
     */
    public function countTotal() {
        $sql = "SELECT COUNT(*) as total FROM contacts";
        $result = $this->db->fetchOne($sql);
        return $result ? (int)$result['total'] : 0;
    }
    
    /**
     * Count search results
     */
    public function countSearch($query) {
        $searchTerm = '%' . $query . '%';
        $sql = "SELECT COUNT(*) as total FROM contacts 
                WHERE full_name LIKE ? OR contact_number LIKE ? OR designation LIKE ? OR village LIKE ? OR note LIKE ?";
        $result = $this->db->fetchOne($sql, [$searchTerm, $searchTerm, $searchTerm, $searchTerm, $searchTerm]);
        return $result ? (int)$result['total'] : 0;
    }
}
